zoukankan      html  css  js  c++  java
  • 【2019.9.2】线段树

    upd 9.2:我昨天又双叒叕忘了存...又重打一遍

    线段树

    延迟标记:"该节点曾经被修改,但其子节点尚未被更新"

    模板

    区间加&区间乘

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define lson (o<<1)
    #define rson (o<<1|1)
    const int N=100000+50,M=1e6+50,inf=0x3f3f3f3f;
    int n,m,P,a[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct SegmentTree{ll add,mul,sum;}tree[N<<2];
    void pup(int o){tree[o].sum=((ll)tree[lson].sum+tree[rson].sum)%P;}
    void updnode1(int o,int l,int r,int k){
    	tree[o].sum=(tree[o].sum+(ll)(r-l+1)*k)%P;
    	tree[o].add=((ll)tree[o].add+k)%P;
    }
    void updnode2(int o,int l,int r,int k){
    	tree[o].sum=(ll)tree[o].sum*k%P;
    	tree[o].add=(ll)tree[o].add*k%P;
    	tree[o].mul=(ll)tree[o].mul*k%P;
    }
    void pudw(int o,int l,int r){
    	int mid=l+r>>1;
    	if(tree[o].mul!=1) updnode2(lson,l,mid,tree[o].mul),updnode2(rson,mid+1,r,tree[o].mul),tree[o].mul=1;
    	if(tree[o].add) updnode1(lson,l,mid,tree[o].add),updnode1(rson,mid+1,r,tree[o].add),tree[o].add=0;
    }
    
    void upd1(int o,int l,int r,int x,int y,int k){//区间加
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){updnode1(o,l,r,k);return;}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	upd1(lson,l,mid,x,y,k),upd1(rson,mid+1,r,x,y,k);
    	pup(o);
    }
    void upd2(int o,int l,int r,int x,int y,int k){//区间乘
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){updnode2(o,l,r,k);return;}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	upd2(lson,l,mid,x,y,k),upd2(rson,mid+1,r,x,y,k);
    	pup(o);
    }
    
    int query(int o,int l,int r,int x,int y){
    	if(l>y||r<x) return 0;
    	if(x<=l&&r<=y) return tree[o].sum;
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	int ans=0;
    	ans=((ll)ans+query(lson,l,mid,x,y))%P;
    	ans=((ll)ans+query(rson,mid+1,r,x,y))%P;
    	return ans;
    	
    }
    void build(int o,int l,int r){
    	tree[o].add=0,tree[o].mul=1;
    	if(l==r){tree[o].sum=a[l];return;}
    	int mid=l+r>>1;
    	build(lson,l,mid),build(rson,mid+1,r);
    	pup(o);
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    	//freopen("xor.out","w",stdout);
    	rd(n),rd(m),rd(P);
    	for(int i=1;i<=n;++i) rd(a[i]);
    	build(1,1,n);
    	for(int i=1,opt,x,y,k;i<=m;++i){
    		rd(opt),rd(x),rd(y);
    		if(opt==3) printf("%d
    ",query(1,1,n,x,y));
    		else{
    			rd(k);
    			if(opt==1) upd2(1,1,n,x,y,k);
    			else upd1(1,1,n,x,y,k);
    		}
    	}
    	return 0;
    }
    

    can you answer those queries III

    动态求最大连续子段和+单点修改

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)>(y)?(y):(x))
    #define lson (o<<1)
    #define rson (o<<1|1)
    const int N=5e5+5,M=1000000+5,inf=0x3f3f3f3f;
    int n,m,a[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct SegmentTree{int lmx,rmx,mxs,sum;}tree[N<<2]; 
    void pup(int o){
        tree[o].sum=tree[lson].sum+tree[rson].sum;
        tree[o].lmx=Max(tree[lson].lmx,tree[lson].sum+tree[rson].lmx);
        tree[o].rmx=Max(tree[rson].rmx,tree[rson].sum+tree[lson].rmx);
        tree[o].mxs=Max(Max(tree[lson].mxs,tree[rson].mxs),tree[lson].rmx+tree[rson].lmx);
    }
    
    
    
    void mdf(int o,int l,int r,int x,int k){
        if(l==r){tree[o]=(SegmentTree){k,k,k,k};return;}
        int mid=l+r>>1;
        if(x<=mid) mdf(lson,l,mid,x,k);
        else mdf(rson,mid+1,r,x,k);
        pup(o);
    }
    
    SegmentTree query(int o,int l,int r,int x,int y){
        if(x<=l&&r<=y) return tree[o];
        int mid=l+r>>1;
        if(y<=mid) return query(lson,l,mid,x,y);
        else if(x>mid) return query(rson,mid+1,r,x,y);
        else{
            SegmentTree ls,rs,ans;
            ls=query(lson,l,mid,x,y),rs=query(rson,mid+1,r,x,y);
            ans.sum=ls.sum+rs.sum;
            ans.lmx=Max(ls.lmx,ls.sum+rs.lmx);
            ans.rmx=Max(rs.rmx,rs.sum+ls.rmx);
            ans.mxs=Max(Max(ls.mxs,rs.mxs),ls.rmx+rs.lmx);
            return ans;
        }
    }
    void build(int o,int l,int r){
        if(l==r){tree[o]=(SegmentTree){a[l],a[l],a[l],a[l]};return;}
        int mid=l+r>>1;
        build(lson,l,mid),build(rson,mid+1,r);
        pup(o);
    }
    
    int main(){
        freopen("in.txt","r",stdin);
    //  freopen("numbers.out","w",stdout);
        rd(n),rd(m);
        for(int i=1;i<=n;++i) rd(a[i]);
        build(1,1,n);
        for(int i=1,opt,x,y;i<=m;++i){
            rd(opt),rd(x),rd(y);
            if(opt==2) mdf(1,1,n,x,y);
            else{
                if(x>y) swap(x,y);
                printf("%d
    ",query(1,1,n,x,y).mxs);
            }
        }
        return 0;
    }
    

    Interval GCD

    给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

    1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

    2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

    对于每个询问,输出一个整数表示答案。

    (gcd(x,y)=gcd(x,y-x))可推到(gcd(x,y,z)=gcd(x,y-x,z-y)) 由数学归纳法可证明该性质对任意多个整数都成立

    用线段树维护差分序列的gcd 然后查询时求出(gcd(a[l],ask(1,1,n,l+1,r)))

    ==太菜了只能看着标程来 囫囵吞枣地过了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)>(y)?(y):(x))
    #define lson (o<<1)
    #define rson (o<<1|1)
    const int N=5e5+5,M=1000000+5,inf=0x3f3f3f3f;
    int n,m;
    ll a[N],b[N],c[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    ll gcd(ll A,ll B){return B?gcd(B,A%B):A;}
    
    struct SegmentTree{ll gcd;}tree[N<<2]; 
    void pup(int o){
    	tree[o].gcd=gcd(tree[lson].gcd,tree[rson].gcd);
    }
    void mdf(int o,int l,int r,int x,ll k){
    	if(l==r){tree[o].gcd+=k;return;}
    	int mid=l+r>>1;
    	if(x<=mid) mdf(lson,l,mid,x,k);
    	else mdf(rson,mid+1,r,x,k);
    	pup(o);
    }
    ll query(int o,int l,int r,int x,int y){
    	if(x<=l&&r<=y) return Abs(tree[o].gcd);
    	int mid=l+r>>1;
    	ll ans=0;
    	if(x<=mid) ans=gcd(ans,query(lson,l,mid,x,y));
    	if(y>mid) ans=gcd(ans,query(rson,mid+1,r,x,y));
    	return Abs(ans);
    }
    void build(int o,int l,int r){
    	if(l==r){tree[o].gcd=b[l];return;}
    	int mid=l+r>>1;
    	build(lson,l,mid),build(rson,mid+1,r);
    	pup(o);
    }
    
    int lowbit(int x){return x&(-x);}
    void add(int x,ll y){
    	for(;x<=n;x+=lowbit(x)) c[x]+=y;
    }
    ll ask(int x){
    	ll ans=0;
    	for(;x;x-=lowbit(x)) ans+=c[x];
    	return ans;
    }
    
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("numbers.out","w",stdout);
    	rd(n),rd(m),a[0]=0;
    	for(int i=1;i<=n;++i) rd(a[i]),b[i]=a[i]-a[i-1];
    	build(1,1,n);
    	while(m--){
    		char opt[5];int x,y;ll k;
    		scanf("%s",opt);rd(x),rd(y);
    		if(opt[0]=='C'){
    			rd(k);
    			mdf(1,1,n,x,k);
    			if(y<n) mdf(1,1,n,y+1,-k);
    			add(x,k),add(y+1,-k);
    		}
    		else{
    			ll nw=a[x]+ask(x),val=x<y?query(1,1,n,x+1,y):0;
    			printf("%lld
    ",gcd(nw,val));
    		}
    	}
        return 0;
    }
    

    yyb的线段树总结吼啊! https://www.cnblogs.com/cjyyb/p/8567674.html

    无聊的数列

    等差数列可以写成(a+l*k)

    发现是单点查询 可以用线段树维护数组(a)的差分数组(b)

    在区间([l,r])加上一个首项为(k)步长为(d)的等差数列 所以(b[l]+k , b[i]+d(iin (l,r]) , b[r+1]-(k+(r-l)*d))

    所以就是一个区间加+单点查询

    线段树

    (QAQ)第一遍打忘了pushdown之后把懒标记清空

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define rg register
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)>(y)?(y):(x))
    #define Abs(x) ((x)<0?-(x):(x))
    #define lson (o<<1)
    #define rson (o<<1|1)
    const int N=1e5+5,M=32000+5,inf=0x3f3f3f3f;
    int n,m,a[N],b[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct SegmentTree{int sum,add;}tree[N<<2];
    void pup(int o){tree[o].sum=tree[lson].sum+tree[rson].sum;}
    void updnode(int o,int l,int r,int k){
    	tree[o].sum+=(r-l+1)*k;
    	tree[o].add+=k;
    }
    void pudw(int o,int l,int r){
    	int mid=l+r>>1;
    	if(tree[o].add!=0) updnode(lson,l,mid,tree[o].add),updnode(rson,mid+1,r,tree[o].add),tree[o].add=0;
    }
    void upd(int o,int l,int r,int x,int y,int k){
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){updnode(o,l,r,k);return;}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	upd(lson,l,mid,x,y,k),upd(rson,mid+1,r,x,y,k);
    	pup(o);
    }
    int query(int o,int l,int r,int x,int y){
    	if(l>y||r<x) return 0;
    	if(x<=l&&r<=y) return tree[o].sum;
    	pudw(o,l,r);
    	int mid=l+r>>1,ans=0;
    	ans+=query(lson,l,mid,x,y)+query(rson,mid+1,r,x,y);
    	return ans;
    }
    
    void build(int o,int l,int r){
    	tree[o].add=0;
    	if(l==r){tree[o].sum=b[l];return;}
    	int mid=l+r>>1;
    	build(lson,l,mid),build(rson,mid+1,r);
    	pup(o);
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("numbers.out","w",stdout);
    	rd(n),rd(m);a[0]=0;
    	for(int i=1;i<=n;++i) rd(a[i]),b[i]=a[i]-a[i-1];
    	build(1,1,n);
    	for(int i=1,opt,x,y,k,d;i<=m;++i){
    		rd(opt);
    		if(opt==1){
    			rd(x),rd(y),rd(k),rd(d);
    			upd(1,1,n,x,x,k),upd(1,1,n,x+1,y,d),upd(1,1,n,y+1,y+1,-(k+(y-x)*d));
    		}
    		else{
    			rd(x);
    			printf("%d
    ",query(1,1,n,1,x));
    		}
    	}
        return 0;
    }
    

    [SHOI2008]堵塞的交通

    这道题怎么奇奇怪怪的==

    真的很神奇! 不看题解根本想不出来这么多细节(QAQ)

    线段树维护连通性

     从一座城市走到另一座城市,一共有4种方案。

      img

      若两城市在同一行(比如说s1,s2),那么:

    1. s1-->s2
    2. s1-->s3,s3-->s2
    3. s1-->s4,s4-->s2
    4. s1-->s3,s3-->s4,s4-->s2

      若两城市不在同一行(比如说s1,s4),那么:

    1. s1-->s3,s3-->s4
    2. s1-->s2,s2-->s4
    3. s1-->s3,s3-->s2,s2-->s4
    4. s1-->s4

    每个节点表示一个([l,r])的矩阵 mid即((l+r)/2)

    ​ U:第一行mid,mid+1两列之间是否联通

      D:第二行mid,mid+1两列之间是否联通

      l:s1,s3是否联通

      r:s2,s4是否联通

      u:s1,s2是否联通

      d:s3,s4是否联通

      q:s1,s4是否联通

      p:s3,s2是否联通

    对于pup中 luogu第一篇题解的dalao解释

    QAQ真的很想die

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define rg register
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)>(y)?(y):(x))
    #define Abs(x) ((x)<0?-(x):(x))
    #define lson (o<<1)
    #define rson (o<<1|1)
    const int N=1e5+5,M=32000+5,inf=0x3f3f3f3f;
    int n,m,a[N],b[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct SegmentTree{
    	bool U,D,l,r,u,d,p,q;
    }tree[N<<2];
    void pup(SegmentTree &x,SegmentTree l,SegmentTree r){
    	x.u=(l.u&r.u&x.U)|(l.q&x.D&r.p);
    	x.d=(l.d&r.d&x.D)|(l.p&x.U&r.q);
    	x.l=l.l|(l.u&x.U&r.l&x.D&l.d);
    	x.r=r.r|(r.u&x.U&l.r&x.D&r.d);
    	x.p=(l.d&x.D&r.p)|(l.p&x.U&r.u);
    	x.q=(l.u&x.U&r.q)|(l.q&x.D&r.d);
    }
    
    void mdf1(int o,int l,int r,int c,int row,int k){
    	int mid=l+r>>1;
    	if(mid==c){
    		if(row==1) tree[o].U=k;
    		else tree[o].D=k;
    		pup(tree[o],tree[lson],tree[rson]);
    		return;
    	}
    	if(c<=mid) mdf1(lson,l,mid,c,row,k);
    	else mdf1(rson,mid+1,r,c,row,k);
    	pup(tree[o],tree[lson],tree[rson]);
    }
    void mdf2(int o,int l,int r,int c,int k){
    	int mid=l+r>>1;
    	if(l==r){tree[o].l=tree[o].r=tree[o].p=tree[o].q=k;return;}
    	if(c<=mid) mdf2(lson,l,mid,c,k);
    	else mdf2(rson,mid+1,r,c,k);
    	pup(tree[o],tree[lson],tree[rson]);
    }
    
    SegmentTree query(int o,int l,int r,int x,int y){
    	int mid=l+r>>1;
    	if(x<=l&&r<=y) return tree[o];
    	if(y<=mid) return query(lson,l,mid,x,y);
    	else if(x>mid) return query(rson,mid+1,r,x,y);
    	else{
    		SegmentTree ans=tree[o];
    		pup(ans,query(lson,l,mid,x,y),query(rson,mid+1,r,x,y));
    		return ans;
    	}
    }
    void build(int o,int l,int r){
    	if(l==r){tree[o].U=tree[o].D=tree[o].u=tree[o].d=1;return;}
    	int mid=l+r>>1;
    	build(lson,l,mid),build(rson,mid+1,r);
    	pup(tree[o],tree[lson],tree[rson]);
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("numbers.out","w",stdout);
    	rd(n);
    	char opt[10];
    	build(1,1,n);
    	while(scanf("%s",opt)&&opt[0]!='E'){
    		int r1,c1,r2,c2;
    		rd(r1),rd(c1),rd(r2),rd(c2);
    		if(c1>c2) swap(c1,c2),swap(r1,r2);
    		if(opt[0]=='O'){
    			if(r1==r2) mdf1(1,1,n,c1,r1,1);
    			else mdf2(1,1,n,c1,1);
    		}
    		else if(opt[0]=='C'){
    			if(r1==r2) mdf1(1,1,n,c1,r1,0);
    			else mdf2(1,1,n,c1,0);
    		}
    		else{
    			SegmentTree l=query(1,1,n,1,c1),r=query(1,1,n,c2,n),x=query(1,1,n,c1,c2);
    			bool ans=0;
    			if(r1==1&&r2==1)
    			ans=x.u|(l.r&x.p)|(r.l&x.q)|(l.r&x.d&r.l);
    			if(r1==1&&r2==2)
    			ans=x.q|(l.r&x.d)|(x.u&r.l)|(l.r&x.p&r.l);
    			if(r1==2&&r2==1)
    			ans=x.p|(x.d&r.l)|(l.r&x.u)|(l.r&x.q&r.l);
    			if(r1==2&&r2==2)
    			ans=x.d|(l.r&x.q)|(x.p&r.l)|(l.r&x.u&r.l);
    			puts(ans?"Y":"N");
    		}
    	}
        return 0;
    }
    

    【UOJ228基础数据结构练习题】

    ==看到开根 第一反应之前那个区间开根 每个数最多只会开5次

    可是这题又有加法操作 如果这次开完 下一次又加回来不断循环就爆炸了

    如果一段区间的数开方后减少的值相同 我们就可以转化为区间减法 这样复杂度就可以保证了==

    比如8 9开方后是2 3减少的值都为6

    所以线段树还要再维护区间最大和最小 每次开方时特判其减少的值是否相等

    yyb大佬的总结

    这类题目的重点在于这些特殊操作的处理

    此时的思考的主要方向已经不是线段树如何使用了

    而是想清楚当前操作具有的特殊性质

    再来相应地在线段树上维护所需要的东西

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)>(y)?(y):(x))
    #define ls (o<<1)
    #define rs (o<<1|1)
    const int N=1e5+5,M=32000+5,inf=0x3f3f3f3f;
    int n,m,a[N],b[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct node{ll mx,mn,add,sum;}t[N<<2];
    void pup(int o){
    	t[o].sum=t[ls].sum+t[rs].sum;
    	t[o].mx=Max(t[ls].mx,t[rs].mx);
    	t[o].mn=Min(t[ls].mn,t[rs].mn);
    }
    void updnode(int o,int l,int r,ll k){
    	t[o].sum+=(ll)(r-l+1)*k;
    	t[o].add+=k,t[o].mn+=k,t[o].mx+=k;
    }
    void pudw(int o,int l,int r){
    	int mid=l+r>>1;
    	if(t[o].add!=0) updnode(ls,l,mid,t[o].add),updnode(rs,mid+1,r,t[o].add),t[o].add=0;
    }
    
    void upd1(int o,int l,int r,int x,int y,ll k){
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){updnode(o,l,r,k);return;}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	upd1(ls,l,mid,x,y,k),upd1(rs,mid+1,r,x,y,k);
    	pup(o);
    }
    void upd2(int o,int l,int r,int x,int y){
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){
    		ll A=t[o].mn-(ll)sqrt(t[o].mn),B=t[o].mx-(ll)sqrt(t[o].mx);
    		if(A==B){updnode(o,l,r,-A);return;}
    	}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	upd2(ls,l,mid,x,y),upd2(rs,mid+1,r,x,y);
    	pup(o);
    }
    ll query(int o,int l,int r,int x,int y){
    	if(l>y||r<x) return 0;
    	if(x<=l&&r<=y) return t[o].sum;
    	pudw(o,l,r);
    	int mid=l+r>>1;ll ans=0ll;
    	ans+=query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
    	pup(o);
    	return ans;
    }
    void build(int o,int l,int r){
    	t[o].add=0;
    	if(l==r){t[o].mn=t[o].mx=t[o].sum=a[l];return;}
    	int mid=l+r>>1;
    	build(ls,l,mid),build(rs,mid+1,r);
    	pup(o);
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("numbers.out","w",stdout);
    	rd(n),rd(m);
    	for(int i=1;i<=n;++i) rd(a[i]);
    	build(1,1,n);
    	for(int i=1,opt,x,y,k;i<=m;++i){
    		rd(opt),rd(x),rd(y);
    		if(opt==1)
    			rd(k),upd1(1,1,n,x,y,k);
    		else if(opt==2) upd2(1,1,n,x,y);
    		else printf("%lld
    ",query(1,1,n,x,y));
    	}
        return 0;
    }
    

    [HEOI2016/TJOI2016]排序]

    luogu2824 HEOI2016/TJOI2016]排序 BZOJ4552

    ==显然不能直接排出来 读完题第一反应先离线把询问存下来

    这是一个全排列 二分在位置(Q)上的数字

    每次(check(mid)) 建一个数组(b)来记录改点数值 若(a[i]>mid)(b[i]=1) 其它(b[i]=0)

    对区间([l,r])进行升序排列 就将区间([l,r-cnt])全改为1,区间([r-cnt+1,r])全改为0 ((cnt=区间[l,r]中1的个数)) 降序同理

    然后.....

    01这个方法真的很有用!很巧妙!

    #include<bits/stdc++.h>
    using namespace std;
    #define ls (o<<1)
    #define rs (o<<1|1)
    const int N=1e5+5,M=32000+5,inf=0x3f3f3f3f;
    int n,m,Q,a[N],b[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct node{int sum,tag;}t[N<<2];
    struct Node{int opt,l,r;}q[N];
    void pup(int o){
    	t[o].sum=t[ls].sum+t[rs].sum;
    }
    void updnode(int o,int l,int r,int k){t[o].tag=k,t[o].sum=(r-l+1)*k;}
    void pudw(int o,int l,int r){
    	int mid=l+r>>1;
    	if(t[o].tag!=-1) updnode(ls,l,mid,t[o].tag),updnode(rs,mid+1,r,t[o].tag),t[o].tag=-1;
    }
    void mdf(int o,int l,int r,int x,int y,int k){
    	if(l>y||r<x) return;
    	if(x<=l&&r<=y){updnode(o,l,r,k);return;}
    	pudw(o,l,r);
    	int mid=l+r>>1;
    	mdf(ls,l,mid,x,y,k),mdf(rs,mid+1,r,x,y,k);
    	pup(o);
    }
    int query(int o,int l,int r,int x,int y){
    	if(l>y||r<x) return 0;
    	if(x<=l&&r<=y) return t[o].sum;
    	pudw(o,l,r);
    	int mid=l+r>>1,ans=0;
    	ans+=query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
    	pup(o);
    	return ans;
    }
    void build(int o,int l,int r){
    	t[o].tag=-1;
    	if(l==r){t[o].sum=b[l];return;}
    	int mid=l+r>>1;
    	build(ls,l,mid),build(rs,mid+1,r);
    	pup(o);
    }
    
    bool check(int mid){
    	for(int i=1;i<=n;++i) b[i]=(a[i]>mid);
    	build(1,1,n);
    	for(int i=1;i<=m;++i){
    		int opt=q[i].opt,l=q[i].l,r=q[i].r,cnt;
    		cnt=query(1,1,n,l,r);
    		if(!opt){
    			if(cnt==r-l+1||!cnt) continue;
    			mdf(1,1,n,l,r-cnt,0),mdf(1,1,n,r-cnt+1,r,1);
    		}
    		else{
    			if(cnt==r-l+1||!cnt) continue;
    			mdf(1,1,n,l,l+cnt-1,1),mdf(1,1,n,l+cnt,r,0);
    		}
    	}
    	return query(1,1,n,Q,Q);
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("numbers.out","w",stdout);
    	rd(n),rd(m);
    	for(int i=1;i<=n;++i) rd(a[i]);
    	for(int i=1;i<=m;++i) rd(q[i].opt),rd(q[i].l),rd(q[i].r);
    	rd(Q);
    	int l=0,r=n,mid;
    	while(l<r){
    		mid=l+r>>1;
    		if(check(mid)) l=mid+1;
    		else r=mid;
    	}
    	printf("%d
    ",r);
        return 0;
    }
    
  • 相关阅读:
    容器适配器————priority_queue
    容器适配器————queue
    容器适配器之总结
    序列式容器之总结
    序列式容器————forward_list
    序列式容器————list
    序列式容器————dequeue
    13.软件项目管理与敏捷方法——如何变更职责笔记
    10.软件项目管理与敏捷方法——沟通管理笔记
    09.软件项目管理与敏捷方法——人力资源管理笔记
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/11446227.html
Copyright © 2011-2022 走看看