正题
一看到这题就心碎emm,好好睡觉不行吗。。。
关键看完这道题,你就要想到,用树链剖分+线段树来维护,因为在这方面线段树是最灵活而且是最万能的。我们就要想,怎么去进行线段树合并。
首先,您不可能建2^64个线段树。然后第i个线段树维护i经过这个线段树的某个区间所留下来的值。
这样的时间复杂的虽然比起暴力来好像快很多,但是细想还是不行。
想着拆位优化。
比如说当前的z是00101001.
那么我们就可以取00000000~00101001.
位运算就是每一位之间的操作都不影响,所以我们可以把它们拆成一位一位进去跑。
如果第一位(最高位)放入一个0,跑出来的结果是0.
放入一个1,跑出来的结果是1.
那么我们肯定会优先选择有价值的,因为我们是从高位往底位做,所以就算后面的1全部取,也没有当前取1大,所以当前优先取大。
那么我们对于每一个位置建立一棵线段树,然后进行维护。跑一遍合并之后发现我们的时间复杂度为
m logn logn 64*2
所以是接近1亿的。
那么我们都说了,不同两位之间不会影响,何尝不把它们同时做,用unsigned long long 来存储呢?
那么我们之前是对于每一位放0和放1跑,现在我们不如放000000...和111111...来跑。
所以线段树中的每一个节点都只需要存两个值,一个是000000...放进该区间跑出来的权值,另一个是111111...放进该区间跑出来的权值。
然后我们就发现,在向上维护的过程中遇到了麻烦。
比如说00000000放入左子树跑出来的答案是01001011.
但是右子树的节点只存储了两个值00000000放进去跑和11111111放进去跑。
那么我们怎么向上维护呢?
我们需要做的是不是将左子树中的1,改成这一位为1时放入右子树后的得出来的值。
那么得出来的一个unsigned long long 我们把它设为ans
ans中为1的条件是什么?
左子树的答案中为1的那位,在右子树把1放进去时也为1.
左子树的答案中为0的那位,在右子树把0放进去时也为1
所以思考一下位运算,就可以作出O(1)的向上维护
ans[now][0]=(ans[rs[now]][1]&ans[ls[now]][0])|(ans[rs[now]][0]&(~ans[ls[now]][0]));
ans[now][1]=(ans[rs[now]][1]&ans[ls[now]][1])|(ans[rs[now]][0]&(~ans[ls[now]][1]));
然后依据这个来更新就可以了,这部分是关键哦~
另外还要说的,因为位运算的操作不能颠倒,所以必须从x往y做。
所以我们做的顺序可能是(7->1) (8->11)
顺序就会有正和倒的区分,所以要建两棵线段树。
最后把得出来的两个值(分别是把000...放进去和把111...放进去的权值)
做一遍贪心(上面),就可以知道最大的v。
// luogu-judger-enable-o2
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int ls[1000010],rs[1000010];//0为从左往右放,1为从右往左放
unsigned long long ans[1000010][2][2];
int root;
int n,m,k;
unsigned long long t[100010];
int op[200010];
struct edge{
int y,next;
}u[200010];
int first[200010];
int tot[200010],son[200010],top[200010],image[200010],fa[200010],dep[200010];
int len=0;
int v,opt;
unsigned long long tt;
unsigned long long piece=0-1;
void ins(int x,int y){
len++;
u[len].y=y;u[len].next=first[x];first[x]=len;
}
void dfs_1(int x){
tot[x]=1;
for(int i=first[x];i!=0;i=u[i].next){
int y=u[i].y;
if(y!=fa[x]){
fa[y]=x;
dep[y]=dep[x]+1;
dfs_1(y);
if(tot[y]>tot[son[x]]) son[x]=y;
tot[x]+=tot[y];
}
}
}
void dfs_2(int x,int tp){
top[x]=tp;image[x]=++len;
if(son[x]!=0) dfs_2(son[x],tp);
for(int i=first[x];i!=0;i=u[i].next){
int y=u[i].y;
if(y!=fa[x] && y!=son[x]) dfs_2(y,y);
}
}
void update(int&now,int x,int y){
if(now==0) now=++len;
int mid=(x+y)/2;
if(x==y){
if(opt==1){
ans[now][0][0]=ans[now][0][1]=(0&tt);
ans[now][1][0]=ans[now][1][1]=(piece&tt);
}
else if(opt==2){
ans[now][0][0]=ans[now][0][1]=(0|tt);
ans[now][1][0]=ans[now][1][1]=(piece|tt);
}
else if(opt==3){
ans[now][0][0]=ans[now][0][1]=(0^tt);
ans[now][1][0]=ans[now][1][1]=(piece^tt);
}
return ;
}
if(v<=mid) update(ls[now],x,mid);
else update(rs[now],mid+1,y);
ans[now][0][0]=(ans[rs[now]][1][0]&ans[ls[now]][0][0])|(ans[rs[now]][0][0]&(~ans[ls[now]][0][0]));
ans[now][1][0]=(ans[rs[now]][1][0]&ans[ls[now]][1][0])|(ans[rs[now]][0][0]&(~ans[ls[now]][1][0]));
ans[now][0][1]=(ans[ls[now]][1][1]&ans[rs[now]][0][1])|(ans[ls[now]][0][1]&(~ans[rs[now]][0][1]));
ans[now][1][1]=(ans[ls[now]][1][1]&ans[rs[now]][1][1])|(ans[ls[now]][0][1]&(~ans[rs[now]][1][1]));
}
unsigned long long get_change(int now,int l,int r,int x,int y,bool w,bool wh){
if(l==x && r==y) return ans[now][w][wh];
int mid=(x+y)/2;
if(r<=mid) return get_change(ls[now],l,r,x,mid,w,wh);
else if(mid<l) return get_change(rs[now],l,r,mid+1,y,w,wh);
else{
unsigned long long temp;
if(wh==false){
temp=get_change(ls[now],l,mid,x,mid,w,wh);
temp=(get_change(rs[now],mid+1,r,mid+1,y,true,wh)&temp)|(get_change(rs[now],mid+1,r,mid+1,y,false,wh)&(~temp));
}
else {
temp=get_change(rs[now],mid+1,r,mid+1,y,w,wh);
temp=(get_change(ls[now],l,mid,x,mid,true,wh)&temp)|(get_change(ls[now],l,mid,x,mid,false,wh)&(~temp));
}
return temp;
}
}
int l[2][30],r[2][30];
int tota[2],total;
unsigned long long solve(){
int x,y;
unsigned long long z;
scanf("%d %d %llu",&x,&y,&z);
int tx=top[x],ty=top[y];
bool tf=true;
tota[0]=tota[1]=0;
while(tx!=ty){
if(dep[tx]>dep[ty]){
swap(x,y);
swap(tx,ty);
tf^=true;
}
l[tf][++tota[tf]]=image[ty];
r[tf][tota[tf]]=image[y];
y=fa[ty];ty=top[y];
}
if(dep[x]>dep[y]){
swap(x,y);
tf^=true;
}
l[tf][++tota[tf]]=image[x];
r[tf][tota[tf]]=image[y];
unsigned long long op1=0,op2=0-1;
for(int i=1;i<=tota[0];i++){
op1=(get_change(root,l[0][i],r[0][i],1,n,true,true)&op1)|(get_change(root,l[0][i],r[0][i],1,n,false,true)&(~op1));
op2=(get_change(root,l[0][i],r[0][i],1,n,true,true)&op2)|(get_change(root,l[0][i],r[0][i],1,n,false,true)&(~op2));
}
for(int i=tota[1];i>=1;i--){
op1=(get_change(root,l[1][i],r[1][i],1,n,true,false)&op1)|(get_change(root,l[1][i],r[1][i],1,n,false,false)&(~op1));
op2=(get_change(root,l[1][i],r[1][i],1,n,true,false)&op2)|(get_change(root,l[1][i],r[1][i],1,n,false,false)&(~op2));
}
unsigned long long temp=((unsigned long long)1<<63);
unsigned long long vv=0;
for(int i=63;i>=0;i--){
if(op1&temp) vv+=temp;
else if((op2&temp) && temp<=z){
vv+=temp;
z-=temp;
}
temp>>=1;
}
return vv;
}
void change(){
int x,y;
unsigned long long z;
scanf("%d %d %llu",&x,&y,&z);
v=image[x];opt=y;
tt=z;
update(root,1,n);
}
int main(){
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d %llu",&op[i],&t[i]);
for(int i=1;i<=n-1;i++){
int x,y;
scanf("%d %d",&x,&y);
ins(x,y);
ins(y,x);
}
dep[1]=1;dfs_1(1);
len=0;dfs_2(1,1);
len=0;
for(int i=1;i<=n;i++){
v=image[i];opt=op[i];
tt=t[i];
update(root,1,n);
}
int type;
while(m--){
scanf("%d",&type);
if(type==1) printf("%llu\n",solve());
else change();
}
}