[2018雅礼省选集训4-2]Problem A 位运算+势能分析线段树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DOFYPXY/article/details/79960747

首先把看成把某些位强制变为0,把看成把某些位强制变为1。那么对于一次修改,如果一个区间内的数这些位都相同就打标记,否则暴力处理左右区间即可。
先证明这样做的复杂度是对的,设fi=flsoni+frsoni+k=020[ik],那么f(root)一开始是O(20N)的,每次修改最多增加O(20logN),而每次访问一个新节点f(root)至少减少1,所以复杂度是O(20NlogN)的。
至于打标记,可以用一个与标记和一个或标记来表示(注意认为规定先后顺序),判断一些位是否全相同,可以维护区间与和、区级或和,与和为1或者或和为0的位就是全相同的了。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r>>1)
#define N 200010
using namespace std;
const int R=(1<<20)-1;
int n,q,a[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
struct tree
{
    int mx,h,y,bh,by;
    tree *ls,*rs;
    tree(){h=0;y=R;}
    void update()
    {
        mx=max(ls->mx,rs->mx);
        bh=ls->bh|rs->bh;
        by=ls->by&rs->by;
    }
    void cal(int dh,int dy)
    {
        mx=(mx&dy)|dh;bh=(bh&dy)|dh;by=(by&dy)|dh;
        y=(y&dy);h=(h&dy)|dh;
    }
    void pushdown()
    {
        ls->cal(h,y);
        rs->cal(h,y);
        h=0;y=R;
    }
    void build(int l,int r)
    {
        if(l==r) {mx=bh=by=a[l];return ;}
        (ls=new tree)->build(l,mid);
        (rs=new tree)->build(mid+1,r);
        update();
    }
    void mdf(int l,int r,int lx,int rx,int dh,int dy)
    {
        if(l==lx&&r==rx)
        {
            int t=(by|(R^bh));
            if(((dh|t)==t)&&(((R^dy)|t)==t)) {cal(dh,dy);return ;} 
        }
        pushdown();
        if(rx<=mid) ls->mdf(l,mid,lx,rx,dh,dy);
        else if(lx>mid) rs->mdf(mid+1,r,lx,rx,dh,dy);
        else ls->mdf(l,mid,lx,mid,dh,dy),rs->mdf(mid+1,r,mid+1,rx,dh,dy);
        update();
    }
    int qry(int l,int r,int lx,int rx)
    {
        if(l==lx&&r==rx) return mx;
        pushdown();
        if(rx<=mid) return ls->qry(l,mid,lx,rx);
        if(lx>mid) return rs->qry(mid+1,r,lx,rx);
        return max(ls->qry(l,mid,lx,mid),rs->qry(mid+1,r,mid+1,rx)); 
    }
}*xtr;
int main()
{
    n=read();q=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    (xtr=new tree)->build(1,n); 
    while(q--)
    {
        int opt=read(),l=read(),r=read(),x;
        if(opt==1)  xtr->mdf(1,n,l,r,0,read());
        if(opt==2)  xtr->mdf(1,n,l,r,read(),R);
        if(opt==3)  printf("%d\n",xtr->qry(1,n,l,r));
    }
    return 0;
}
阅读更多

没有更多推荐了,返回首页