题目背景
刚立完Flag我就挂了WC和THUWC。。。
时间限制0.5s,空间限制128MB
因为Claris大佬帮助一周目由乃通过了Deus的题,所以一周目的由乃前往二周目世界找雪辉去了
由于二周目世界被破坏殆尽,所以由乃和雪辉天天都忙着重建世界(其实和MC差不多吧),Deus看到了题问她,总是被告知无可奉告
Deus没办法只能去三周目世界问三周目的由乃OI题。。。
三周目的世界中,因为没有未来日记,所以一切都很正常,由乃天天认真学习。。。
因为Deus天天问由乃OI题,所以由乃去学习了一下OI
由于由乃智商挺高,所以OI学的特别熟练
她在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送
Deus:这个题怎么做呀?
yuno:这个不是NOI2014的水题吗。。。
Deus:那如果出到树上,多组链询问,带修改呢?
yuno:诶。。。???
Deus:这题叫做睡觉困难综合征哟~
虽然由乃OI很好,但是她基本上不会DS,线段树都只会口胡,比如她NOI2016的分数就是100+100+100+0+100+100。。。NOIP2017的分数是100+0+100+100+0+100
所以她还是只能找你帮她做了。。。
题目描述
由乃这个问题越想越迷糊,已经达到了废寝忘食的地步。结果她发现……晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给Deus。
这个神经元是一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示。
为了治疗失眠,Deus可以将一些神经递质放在点x上,初始的刺激值是v_0v0 。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti xi,所以他想问你,最后到y时,希望得到的刺激值尽可能大,所以最大值的v可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值v_0v0 必须是在[0,z]之间。Deus每次都会给你3个数,x,y,z。
不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数x,y,z,意思是把x点的操作修改为y,数值改为z
输入输出格式
输入格式:第一行三个数n,m,k。k的意义是每个点上的数,以及询问中的数值z都 <2^k<2k 。之后n行,每行两个数x,y表示该点的位运算编号以及数值
之后n - 1行,每行两个数x,y表示x和y之间有边相连
之后m行,每行四个数,Q,x,y,z表示这次操作为Q(1位询问,2为更改),x,y,z意义如题所述
对于每个操作1,输出到最后可以造成的最大刺激度v
输入输出样例
5 5 3 1 7 2 6 3 7 3 6 3 1 1 2 2 3 3 4 1 5 1 1 4 7 1 1 3 5 2 1 1 3 2 3 3 3 1 1 3 2
7 1 5
2 2 2 2 2 2 2 1 2 2 2 2 2 1 2 2 2
3
说明
对于30%的数据,n,m <= 1
对于另外20%的数据,k <= 5
对于另外20%的数据,位运算只会出现一种
对于100%的数据,0 <= n , m <= 100000 , k <= 64
做了一下午+一晚上(吃枣药丸。。。),巨坑。。。
首先要会做这题 [NOI2014]起床困难综合症
然后,就可以用LCT搞一大波事情了。。。
每个节点维护两个值:
一个为中序遍历这棵子树的ans0,ans1(分别表示0和MAX(二进制下全为1)跑的答案)
另一个为中序遍历的反向遍历这棵子树的ans0,ans1
还要记得保存这个点的初始操作
合并:对于 中序遍历 的若知道的左边的f0,f1,右边的g0,g1,合并后的h0,h1 有
h0 = (~f0 & g0) | (f0 & g1)
h1 = (~f1 & g0) | (f1 & g1)
反向中序遍历同理。
注意LCT丢到splay后翻转操作的修改。
剩下的与NOI2014那道签到题一样,贪心。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
using namespace std;
unsigned long long MIN=0,MAX=~MIN;
int n,m,q,c=1;
struct node1{
unsigned long long v,w;
}val[MAXN];
struct node2{
int f,flag,son[2];
node1 l,r;
}a[MAXN];
inline long long read(){
long long date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline long long operation(long long x,long long y,int opt){
if(!opt)return x;
switch(opt){
case 1:{x&=y;break;}
case 2:{x|=y;break;}
case 3:{x^=y;break;}
}
return x;
}
inline node1 update(node1 x,node1 y){
node1 rt;
rt.v=(~x.v&y.v)|(x.v&y.w);
rt.w=(~x.w&y.v)|(x.w&y.w);
return rt;
}
inline bool isroot(int rt){
return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
}
inline void pushup(int rt){
if(!rt)return;
a[rt].l=a[rt].r=val[rt];
if(a[rt].son[0]){a[rt].l=update(a[a[rt].son[0]].l,a[rt].l);a[rt].r=update(a[rt].r,a[a[rt].son[0]].r);}
if(a[rt].son[1]){a[rt].l=update(a[rt].l,a[a[rt].son[1]].l);a[rt].r=update(a[a[rt].son[1]].r,a[rt].r);}
}
inline void reserve(int rt){
swap(a[rt].l,a[rt].r);swap(a[rt].son[0],a[rt].son[1]);
a[rt].flag^=1;
}
inline void pushdown(int rt){
if(!rt||!a[rt].flag)return;
reserve(a[rt].son[0]);reserve(a[rt].son[1]);
a[rt].flag^=1;
}
inline void turn(int rt){
int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
if(!isroot(x)){
if(a[y].son[0]==x)a[y].son[0]=rt;
else a[y].son[1]=rt;
}
a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
pushup(x);pushup(rt);
}
void splay(int rt){
int top=0,stack[MAXN];
stack[++top]=rt;
for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
while(top)pushdown(stack[top--]);
while(!isroot(rt)){
int x=a[rt].f,y=a[x].f;
if(!isroot(x)){
if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
else turn(x);
}
turn(rt);
}
}
void access(int rt){
for(int i=0;rt;i=rt,rt=a[rt].f){
splay(rt);
a[rt].son[1]=i;
pushup(rt);
}
}
inline void makeroot(int rt){access(rt);splay(rt);reserve(rt);}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);a[x].f=y;}
inline void answer(unsigned long long sum0,unsigned long long sum1,unsigned long long maxn){
unsigned long long ans=0,t=1;
for(int i=63;i>=0;i--){
if(sum0&(t<<i))ans+=(t<<i);
else if(maxn>=(t<<i)&&(sum1&(t<<i))){
maxn-=(t<<i);
ans+=(t<<i);
}
}
printf("%llu\n",ans);
}
void work1(int x,int y,unsigned long long k){
split(x,y);
answer(a[y].l.v,a[y].l.w,k);
}
void work2(int x,int y,unsigned long long k){
switch(y){
case 1:val[x]=(node1){MIN,k};break;
case 2:val[x]=(node1){k,MAX};break;
case 3:val[x]=(node1){k,~k};break;
}
splay(x);
}
void work(){
int f,x,y;
unsigned long long k;
while(m--){
f=read();x=read();y=read();k=read();
if(f==1)work1(x,y,k);
if(f==2)work2(x,y,k);
}
}
void init(){
int x,y;
unsigned long long k;
n=read();m=read();q=read();
for(int i=1;i<=n;i++){
x=read();k=read();
switch(x){
case 1:val[i]=(node1){MIN,k};break;
case 2:val[i]=(node1){k,MAX};break;
case 3:val[i]=(node1){k,~k};break;
}
}
for(int i=1;i<n;i++){
x=read();y=read();
link(x,y);
}
}
int main(){
init();
work();
return 0;
}