题目传送门:https://www.luogu.org/problemnew/show/P3613
题目分析:yuno好可爱呀!!!
由于不同的位运算之间不满足结合律,所以我们不能将后面的操作合并。又因为位运算时每一位是独立的,我们不妨考虑用LCT维护某一位开始是0,1时,经过这条链后会变成多少。询问时从高位向低位贪心:如果某一位可以选0或1,且选1比选0优,就选1,否则选0;还要注意最高位限制,有点像数位DP。
但每一位单独维护,时间是
O(nlog(n)k)
的,明显超时,所以我们需要一些奇技淫巧。我们在节点上只存两个数f0,f1,分别代表初始值为
0
,
由于我已经将近一个月没有打过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;
}