洛谷P3613:睡觉困难综合征 (LCT+二进制压位)

来源:互联网 发布:防御矩阵无限金币 编辑:程序博客网 时间:2024/05/01 01:17

题目传送门:https://www.luogu.org/problemnew/show/P3613


题目分析:yuno好可爱呀!!!

由于不同的位运算之间不满足结合律,所以我们不能将后面的操作合并。又因为位运算时每一位是独立的,我们不妨考虑用LCT维护某一位开始是0,1时,经过这条链后会变成多少。询问时从高位向低位贪心:如果某一位可以选0或1,且选1比选0优,就选1,否则选0;还要注意最高位限制,有点像数位DP。

但每一位单独维护,时间是O(nlog(n)k)的,明显超时,所以我们需要一些奇技淫巧。我们在节点上只存两个数f0,f1,分别代表初始值为02k1时,最后出来的数是多少。合并Splay左右子树信息时,用左子树的f0&一下右子树的f1,因为0进左子树后变成f0,f0中的1进右子树就变成了右子树的f1;然后将左子树f0中的0和1取反,&一下右子树的f0,原因同上。对f1也进行这样的操作,就能在O(1)的时间进行信息合并。注意,LCT有翻转操作,所以还要维护翻转后的信息g0,g1。由于询问时还是要一位一位地贪心,时间复杂度O(nlog(n)+nk)

由于我已经将近一个月没有打过LCT了,所以一个月前我切LCT像切菜一样,一个月后我切LCT像剁手一样。这道题我是2A的,原因是询问时,我Evert(x),Access(y)后,忘了Splay(Node[x])QAQ。


CODE:

#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;typedef unsigned long long ULL;ULL Max;ULL Get(ULL x,ULL y,int op){    if (op==1) return (x&y);    if (op==2) return (x|y);    return (x^y);}ULL Rev(ULL x){    return (Max^x);}struct Tnode{    ULL f0,f1,g0,g1,val;    int opt,path_parent;    bool flip;    Tnode *son[2],*fa;    int Get_d() { return (fa->son[1]==this); }    void Connect(Tnode *P,int d) { (son[d]=P)->fa=this; }    void Push_down()    {        if (flip)        {            swap(son[0],son[1]);            if (son[0])            {                swap(son[0]->f0,son[0]->g0);                swap(son[0]->f1,son[0]->g1);                son[0]->flip^=1;            }            if (son[1])            {                swap(son[1]->f0,son[1]->g0);                swap(son[1]->f1,son[1]->g1);                son[1]->flip^=1;            }            flip=false;        }    }    void Up()    {        if (son[0]) f0=son[0]->f0,f1=son[0]->f1;        else f0=0,f1=Max;        f0=Get(f0,val,opt);        f1=Get(f1,val,opt);        if (son[1])        {            ULL temp=(f0&son[1]->f1);            temp|=(Rev(f0)&son[1]->f0);            f0=temp;            temp=(f1&son[1]->f1);            temp|=(Rev(f1)&son[1]->f0);            f1=temp;        }        if (son[1]) g0=son[1]->g0,g1=son[1]->g1;        else g0=0,g1=Max;        g0=Get(g0,val,opt);        g1=Get(g1,val,opt);        if (son[0])        {            ULL temp=(g0&son[0]->g1);            temp|=(Rev(g0)&son[0]->g0);            g0=temp;            temp=(g1&son[0]->g1);            temp|=(Rev(g1)&son[0]->g0);            g1=temp;        }    }} tree[maxn];Tnode *Node[maxn];int cur=-1;int n,m,k;Tnode *New_node(int op,ULL v){    cur++;    tree[cur].val=v;    tree[cur].opt=op;    tree[cur].path_parent=0;    tree[cur].flip=false;    tree[cur].f0=tree[cur].g0=Get(0,v,op);    tree[cur].f1=tree[cur].g1=Get(Max,v,op);    tree[cur].fa=tree[cur].son[0]=tree[cur].son[1]=NULL;    return tree+cur;}void Push(Tnode *P){    if (!P) return;    Push(P->fa);    P->Push_down();}void Zig(Tnode *P){    int d=P->Get_d();    Tnode *F=P->fa;    if (P->son[!d]) F->Connect(P->son[!d],d);    else F->son[d]=NULL;    if (F->fa) F->fa->Connect(P, F->Get_d() );    else P->fa=NULL;    P->Connect(F,!d);    F->Up();    P->path_parent=F->path_parent;    F->path_parent=0;}void Splay(Tnode *P){    Push(P);    Tnode *F;    while (P->fa)    {        F=P->fa;        if (F->fa) ( P->Get_d()^F->Get_d() )? Zig(P):Zig(F);        Zig(P);    }    P->Up();}void Down(int x){    Splay(Node[x]);    Tnode *&tag=Node[x]->son[1];    if (tag)    {        tag->fa=NULL;        tag->path_parent=x;        tag=NULL;        Node[x]->Up();    }}void Access(int x){    Down(x);    Splay(Node[x]);    int y=Node[x]->path_parent;    while (y)    {        Down(y);        Splay(Node[y]);        Node[y]->Connect(Node[x],1);        Node[y]->Up();        Node[x]->path_parent=0;        x=y;        y=Node[x]->path_parent;    }}void Evert(int x){    Access(x);    Splay(Node[x]);    Node[x]->flip^=1;    swap(Node[x]->f0,Node[x]->g0);    swap(Node[x]->f1,Node[x]->g1);}void Link(int x,int y){    Evert(x);    Splay(Node[x]);    Node[x]->path_parent=y;}int main(){    freopen("3613.in","r",stdin);    freopen("3613.out","w",stdout);    scanf("%d%d%d",&n,&m,&k);    Max=0;    ULL temp=1;    for (int i=0; i<k; i++)    {        Max|=temp;        if (i<k-1) temp<<=1;    }    for (int i=1; i<=n; i++)    {        ULL v;        int op;        scanf("%d%llu",&op,&v);        Node[i]=New_node(op,v);    }    for (int i=1; i<n; i++)    {        int x,y;        scanf("%d%d",&x,&y);        Link(x,y);    }    for (int i=1; i<=m; i++)    {        int id,x,y;        ULL z;        scanf("%d%d%d%llu",&id,&x,&y,&z);        if (id==1)        {            Evert(x);            Access(y);            Splay(Node[x]); //!!!!!            ULL v=temp,p=Node[x]->f0,q=Node[x]->f1,ans=0;            bool High=false;            while (v)            {                if ( (z&v) || High )                {                    if ( (q&v)>(p&v) ) ans|=(q&v);                    else ans|=(p&v),High=true;                }                else ans|=(p&v);                v>>=1;            }            printf("%llu\n",ans);        }        else        {            Splay(Node[x]);            Node[x]->opt=y;            Node[x]->val=z;            Node[x]->Up();        }    }    return 0;}
原创粉丝点击