luogu P3613 睡觉困难综合征

来源:互联网 发布:dt大数据 编辑:程序博客网 时间:2024/04/30 16:54

题目地址
做法和原题差不多原题地址
显然每一个节点开一个大小为K的数组储存答案肯定是不行的
但是k<=64,所以可以开一个unsignedlonglong储存答案
但是合并答案有点恶心
每个节点储存两个值ABA表示INF经过操作后的值,B表示0经过操作后的值
对于一个节点
首先LALB为左边的答案,RARB为右边的答案
以A为例
对于每一位i
如果LA的第i位为0那么A的第i位的值为RA的第i
如果LA的第i位为1那么A的第i位的值为RB的第i

A=((notLA)andRA)or(LAandRB)

同理
B=((notLB)andRA)or(LBandRB)

那么这题就可以树链剖分或者LCT(大常数树)
个人比较推荐树链剖分,因为LCT不仅难调而且还不好写并且常数还巨大
因为LCT有翻转操作所以还要维护RevARevB表示反向操作的答案
总之能不写LCT就不写
ps:但是我还是写的LCT

#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>#define File(S) freopen(S".in","r",stdin),freopen(S".out","w",stdout)using namespace std;namespace Data_stream{    const int IN_LEN=1<<17;    const int OUT_LEN=1<<17;    char buf[IN_LEN],obuf[OUT_LEN],*pcur=obuf,*HEAD=buf,*TAIL=buf,ch;    int BUF,PS=0,Buf[30];    bool sign;    inline char gec(){        if(HEAD==TAIL){            TAIL=(HEAD=buf)+fread(buf,1,IN_LEN,stdin);            if(HEAD==TAIL)return EOF;        }        return *HEAD++;    }    inline void puc(char ch){        if(pcur==obuf+OUT_LEN){            fwrite(obuf,1,OUT_LEN,stdout);            pcur=obuf;        }        *pcur++=ch;    }    template <typename T>    inline int read(T&a){        for(sign=0,ch=gec();!isdigit(ch)&&ch!=EOF;ch=gec())            if(ch=='-')sign=1;        if(ch==EOF)return EOF;        for(a=0;isdigit(ch);ch=gec())a=((a+(a<<2))<<1)+(ch^'0');        if(sign)a=-a;        return 0;    }    template <typename T>    inline void print(T x){        if(x<0)puc('-'),x=-x;        for(;x;x=BUF)            BUF=x/10,Buf[++PS]=x-((BUF+(BUF<<2))<<1);        while(PS)puc('0'^Buf[PS--]);    }    inline void flush(){        fwrite(obuf,1,pcur-obuf,stdout);    }}using namespace Data_stream;//输入输出优化 #define Hf(x) (x->f?((x->f->s[0]==x)||(x->f->s[1]==x)):0)//是否是父亲的实儿子 #define Get(type) (type=(~type&s[1]->Fz)|(type&s[1]->Fe))//A B #define Get_(type) (type=(~type&s[0]->Rfz)|(type&s[0]->Rfe))//RevA RevBtypedef unsigned long long Ul;const int N=2e5+10;const Ul INF=0xffffffffffffffff;//Max unsigned long long inline void Calc(Ul&v,const Ul&val,const int&opt){(!opt)?(v&=val):((opt&1)?(v|=val):(v^=val));}//计算 struct Tree{    Tree(int opt=0,Ul v=0):opt(opt),v(v){Fz=Fe=Rfz=Rfe=0;rev=0;s[0]=s[1]=f=0;}     int opt;    Ul Fz,Fe,Rfz,Rfe,v;    bool rev;    Tree *s[2],*f;      inline void Push(){        if(!rev)return;        rev=0;swap(s[0],s[1]);        swap(Fz,Rfz);swap(Fe,Rfe);//交换正反向操作的答案         if(s[0])s[0]->rev^=1;        if(s[1])s[1]->rev^=1;    }    inline void Update(){        if(s[0])Fz=s[0]->Fz,Fe=s[0]->Fe;        else Fz=0,Fe=INF;        Calc(Fz,v,opt);Calc(Fe,v,opt);        if(s[1])Get(Fz),Get(Fe),Rfz=s[1]->Rfz,Rfe=s[1]->Rfe;        else Rfz=0,Rfe=INF;        Calc(Rfz,v,opt);Calc(Rfe,v,opt);        if(s[0])Get_(Rfz),Get_(Rfe);    }    void*operator new(size_t);}t[N],*cur=t,*vec[N],*stack[N];inline void*Tree::operator new(size_t){return cur++;} int n,m,k,top;inline void Rot(Tree *p){    Tree *f=p->f;int v=(p!=f->s[0]);    if(f->s[v]=p->s[v^1])f->s[v]->f=f;    if(Hf(f))f->f->s[f!=f->f->s[0]]=p;    p->f=f->f;p->s[v^1]=f;f->f=p;    f->Update();p->Update();} inline void Splay(Tree *p){    Tree *last;    stack[++top]=p->s[0];stack[++top]=p->s[1];    for(last=p;Hf(p);p=p->f)stack[++top]=p->f->s[p==p->f->s[0]],stack[++top]=p;    //不知道不开两倍会不会被卡啊    stack[++top]=p;    for(;top;top--)if(stack[top])stack[top]->Push();    for(p=last;Hf(p);Rot(p)){        Tree *f=p->f;        if(Hf(f)) Rot(((p!=f->s[0])^(f!=f->f->s[0]))?p:f);    }}inline void Access(Tree *x){for(Tree *last=0;x;last=x,x=x->f){Splay(x);x->s[1]=last;x->Update();}} inline void MakeRoot(Tree *x){Access(x);Splay(x);x->rev^=1;}inline void link(Tree*x,Tree*y){MakeRoot(x);x->f=y;}inline void cut(Tree*x,Tree*y){MakeRoot(x);Access(y);Splay(x);x->s[1]=y->f=0;x->Update();}int main(){    int x,y,type;    Ul z;    read(n);read(m);read(k);    for(int i=1;i<=n;i++)read(t[i].opt),t[i].opt--,read(t[i].v),t[i].Update();    for(int i=1;i<n;i++)read(x),read(y),link(t+x,t+y);     while(m--){        read(type);read(x);read(y);read(z);        if(type&1){            MakeRoot(t+x);Access(t+y);Splay(t+y);            Ul Fz=t[y].Fz,Fe=t[y].Fe,Ans=0;            for(int i=k-1;~i;i--){                Ul P=(Ul)1<<i;                 if((Fe&P)&&!(Fz&P)&&(z>=P))Ans|=P,z-=P;                else Ans|=Fz&P;            }//与原题差不多             printf("%llu\n",Ans);        }        else{            Splay(t+x);t[x].opt=y-1;t[x].v=z;            //我这里一开始忘了减一            t[x].Update();        }    }    return 0;}