cf1108E2 线段树类似扫描线

Posted zsben991126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1108E2 线段树类似扫描线相关的知识,希望对你有一定的参考价值。

/*
有点像扫描线 
思路:从左到右枚举每个点,枚举到点i时,把所有以i为起点的区间的影响删去
再加上以i-1为结尾的区间的影响 
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int n,m,a[maxn];
struct Inv{int l,r;}p[400];

int lazy[maxn<<2],Min[maxn<<2];
inline void pushup(int rt){
    Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}
inline void pushdown(int rt){
    if(lazy[rt]){
        lazy[rt<<1]+=lazy[rt];lazy[rt<<1|1]+=lazy[rt];
        Min[rt<<1]+=lazy[rt];Min[rt<<1|1]+=lazy[rt];
        lazy[rt]=0; 
    }
}
void build(int l,int r,int rt){
    lazy[rt]=0;
    if(l==r){Min[rt]=a[l];return;}
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,int l,int r,int rt,int val){
    if(L<=l && R>=r){
        Min[rt]+=val,lazy[rt]+=val;return;
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m)update(L,R,lson,val);
    if(R>m)update(L,R,rson,val);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r){return Min[rt];}
    pushdown(rt);
    int m=l+r>>1,res=99999999;
    if(L<=m)res=min(res,query(L,R,lson));
    if(R>m)res=min(res,query(L,R,rson));
    pushup(rt);
    return res;
}

vector<int>ans[100005];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)scanf("%d%d",&p[i].l,&p[i].r);    
    
    int Max=-1,index=0;
    build(1,n,1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(p[j].l<=i&&p[j].r>=i){//该区间和当前坐标有关 
                if(i!=1 && !(p[j].l<=i-1&&p[j].r>=i-1))//和左边结点无关
                    update(p[j].l,p[j].r,1,n,1,1);//加上这段的值 
                continue; 
            }
            ans[i].push_back(j);
            //算上之前没算上的区间 
            if(i==1 || p[j].l<=i-1&&p[j].r>=i-1)
                update(p[j].l,p[j].r,1,n,1,-1); 
        }
        
        int tmp=query(1,n,1,n,1);
        if(a[i]-tmp>Max){index=i;Max=a[i]-tmp;}
    }
    cout << Max << endl;
    cout << ans[index].size()<<endl;
    for(int i=0;i<ans[index].size();i++)
        cout << ans[index][i]<< " ";
    
} 

 

以上是关于cf1108E2 线段树类似扫描线的主要内容,如果未能解决你的问题,请参考以下文章

CF #535 (Div. 3) E2 Array and Segments (Hard version) 利用线段树进行区间转移

CF720DSlalom 扫描线+线段树

线段树逆序对(偏序)——cf1187D好题!

CF538H Summer Dichotomy 二分图扫描线线段树

CF793G Oleg and chess [线段树优化建边,扫描线,最大流]

线段树维护区间合并——cf1285E