线段树之玄学优化

考场上遇到一道线段树的题,诶,又是一道劝退题,劝退就劝退吧!反正马上就真的退役了....

这个题真的是一点招都没有....区间|和&怎么搞,最后还要查询区间最大值...自闭了...

我们就大胆的用线段树去维护这个东西,考虑怎么剪枝,不然你不会真的暴力递归到最底层吧!

我们想如果我们区间操作的数都是相同的话那不直接打个懒标记不就行了吗?

可如果直接这样的话还是不太行,我们考虑什么时候往下递归是多余的?

就是一个操作对一个区间的影响都相同的时候,我们可以直接打懒标记就行了.

.那之后考虑什么时候操作对我们要操作的数相同。

考虑&x操作,分开考虑x的不同二进制位,如果某一位是1的话,显然对操作的数是无影响的,是1还是1,是0还是0,嘛影响吗!

那只考虑x是0的位,如果我们要操作的数都是这一位都是0或1,显然我们可以用一个区间加减来代替这个与操作.因为都是将这一位的1变成0.

之后考虑如何将x是0的位我们给提取出来.那就做差吧,先&一下,再做差就行,这样的意义:原本是1的位我们还是变为不变,是0的位我们强制变成0,做差就能体现0这一位的差异l.

或运算类似的搞一下...

其实这道题题主要想说的是很多提我们都可以这样优化,就是要判断好什么情况下我们能优化,也就是那些操作是多余的,毕竟暴力出奇迹嘛!

//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define RE register
#define P 999911659
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define pb(x) push_back(x)
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(RE int x=y;x<=z;++x)
#define fep(x,y,z) for(RE int x=y;x>=z;--x)
#define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=200010;
int n,a[N],Q;
struct Tree
{
    int l,r,SrO,OrZ,mx,tag;
    #define l(x) t[x].l
    #define r(x) t[x].r
    #define o(x) t[x].SrO
    #define an(x) t[x].OrZ
    #define mx(x) t[x].mx
    #define tag(x) t[x].tag
}t[N<<2];

char *fs,*ft,buf[1<<15];
inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

inline void pushup(int p)
{
    o(p)=o(p<<1)|o(p<<1|1);
    an(p)=an(p<<1)&an(p<<1|1);
    mx(p)=max(mx(p<<1),mx(p<<1|1));
}


inline void build(int p,int l,int r)
{
    l(p)=l;r(p)=r;
    if(l==r) {o(p)=an(p)=mx(p)=a[l];return;}
    int mid=l+r>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    pushup(p); 
} 

inline void pushdown(int p)
{
    if(tag(p)!=0)
    {
        o(p<<1)+=tag(p);o(p<<1|1)+=tag(p);
        an(p<<1)+=tag(p);an(p<<1|1)+=tag(p);
        mx(p<<1)+=tag(p);mx(p<<1|1)+=tag(p);
        tag(p<<1)+=tag(p);tag(p<<1|1)+=tag(p);
        tag(p)=0;
    }
}

inline void alter(int p,int l,int r,int x,int op)
{
    if(l(p)==r(p)) 
    {
        if(op==1) o(p)&=x,an(p)&=x,mx(p)&=x;
        else o(p)|=x,an(p)|=x,mx(p)|=x;
        return;
    }
    if(l<=l(p)&&r>=r(p))
    {
        if(op==1&&(o(p)&x)-o(p)==(an(p)&x)-an(p))
        {
            int k=(o(p)&x)-o(p);
            mx(p)+=k;o(p)+=k;an(p)+=k;tag(p)+=k;
            return;
        }
        else if(op==2&&(o(p)|x)-o(p)==(an(p)|x)-an(p))
        {
            int k=(o(p)|x)-o(p);
            mx(p)+=k;o(p)+=k;an(p)+=k;tag(p)+=k;
            return;
        }
    }
    pushdown(p);
    int mid=l(p)+r(p)>>1;
    if(l<=mid) alter(p<<1,l,r,x,op);
    if(r>mid) alter(p<<1|1,l,r,x,op);
    pushup(p);
}

inline int ask(int p,int l,int r)
{
    if(l<=l(p)&&r>=r(p)) return mx(p);
    pushdown(p);
    int mid=l(p)+r(p)>>1,ans=0;
    if(l<=mid) ans=max(ans,ask(p<<1,l,r));
    if(r>mid) ans=max(ans,ask(p<<1|1,l,r));
    return ans; 
}

int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    get(n);get(Q);
    rep(i,1,n) get(a[i]);
    build(1,1,n);
    rep(i,1,Q)
    {
        int get(op),get(l),get(r);
        if(op<=2) 
        {
            int get(x);
            alter(1,l,r,x,op);
        }    
        else put(ask(1,l,r));
    }
    return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
View Code

 

posted @ 2020-06-10 16:38  逆天峰  阅读(432)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//