SP16580 QTREE7 - Query on a tree VII(LCT)

题意翻译

一棵树,每个点初始有个点权和颜色(输入会给你)

0 u:询问所有u,v路径上的最大点权,要满足u,v路径上所有点颜色相同

1 u:反转u的颜色

2 u w:把u的点权改成w

题解

Qtree6的升级版,建议先做完再来做这题(毕竟那个代码改一改就能做这个了两倍经验岂不美哉)(Qtree6我的题解->这里

我就当你们已经都会Qtree6了(小声)

就是把Qtree6中维护连通块中点的个数,变成维护子树中的最大值就行了

实子树的max直接用,虚子树的max可以直接丢进一个set里

然后就是access的时候虚实边转化,set里要变一下(个人感觉access的时候不需要pushup,因为虚实边转化了,子树最大值是不变的)

然后就是节点0的值赋为-inf省的pushup的时候变为0,因为节点的值会有负的

然后就是update的时候只改一颗树里的竟然对了……可能是因为findroot的时候splay过了吧……

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 #define Col lct[col[x]]
  4 #define inf 0x3f3f3f3f
  5 using namespace std;
  6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  7 char buf[1<<21],*p1=buf,*p2=buf;
  8 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
  9 inline int read(){
 10     #define num ch-'0'
 11     char ch;bool flag=0;int res;
 12     while(!isdigit(ch=getc()))
 13     (ch=='-')&&(flag=true);
 14     for(res=num;isdigit(ch=getc());res=res*10+num);
 15     (flag)&&(res=-res);
 16     #undef num
 17     return res;
 18 }
 19 char sr[1<<21],z[20];int C=-1,Z;
 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 21 inline void print(int x){
 22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
 23     while(z[++Z]=x%10+48,x/=10);
 24     while(sr[++C]=z[Z],--Z);sr[++C]='\n';
 25 }
 26 const int N=100005;
 27 int f[N],Next[N<<1],head[N],ver[N<<1],tot,col[N],n,m,v[N];
 28 inline void add(int u,int v){
 29     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 30     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
 31 }
 32 struct LCT{
 33     int fa[N],ch[N][2],mx[N];
 34     multiset<int> s[N];
 35     LCT(){mx[0]=-inf;}
 36     inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
 37     #define lc ch[x][0]
 38     #define rc ch[x][1]
 39     inline void pushup(int x){
 40         cmax(mx[x]=v[x],max(mx[lc],mx[rc]));
 41         if(!s[x].empty()) cmax(mx[x],*s[x].rbegin());
 42     }
 43     void rotate(int x){
 44         int y=fa[x],z=fa[y],d=ch[y][1]==x;
 45         if(!isroot(y)) ch[z][ch[z][1]==y]=x;
 46         fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y);
 47     }
 48     void splay(int x){
 49         for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
 50             if(!isroot(y))
 51             ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
 52             rotate(x);
 53         }
 54         pushup(x);
 55     }
 56     void access(int x){
 57         for(int y=0;x;x=fa[y=x]){
 58             splay(x);
 59             if(rc) s[x].insert(mx[rc]);
 60             if(rc=y) s[x].erase(s[x].find(mx[y]));
 61         }
 62     }
 63     int findroot(int x){
 64         access(x),splay(x);
 65         while(lc) x=lc;
 66         splay(x);
 67         return x;
 68     }
 69     void link(int x){
 70         access(x),splay(x);
 71         int y=fa[x]=f[x];
 72         access(y),splay(y);
 73         ch[y][1]=x,pushup(y);
 74     }
 75     void cut(int x){
 76         access(x),splay(x);
 77         lc=fa[lc]=0;
 78         pushup(x);
 79     }
 80     void update(int x){
 81         access(x),splay(x);
 82         v[x]=read(),pushup(x);
 83     }
 84 }lct[2];
 85 void dfs(int x){
 86     for(int i=head[x];i;i=Next[i]){
 87         int v=ver[i];
 88         if(v==f[x]) continue;
 89         f[v]=x,dfs(v);
 90     }
 91     Col.link(x);
 92 }
 93 int main(){
 94     //freopen("testdata.in","r",stdin);
 95     n=read();
 96     for(int i=1;i<n;++i){
 97         int u=read(),v=read();
 98         add(u,v);
 99     }
100     for(int i=1;i<=n;++i) col[i]=read();
101     for(int i=1;i<=n;++i) v[i]=read();
102     f[1]=n+1,dfs(1);
103     m=read();
104     while(m--){
105         int op=read(),x=read();
106         switch(op){
107             case 0:print(Col.mx[Col.ch[Col.findroot(x)][1]]);break;
108             case 1:Col.cut(x),col[x]^=1,Col.link(x);break;
109             case 2:Col.update(x);break;
110         }
111     }
112     Ot();
113     return 0;
114 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9436529.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值