QTREE

/*题目大意:维护一棵树,允许修改边权以及查询链上最大值题解:我们将边权转为点权,标记在深度较深的点上,树链剖分后用线段树处理即可
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=20010;
int top[N],nxt[N],v[N],g[N],d[N],son[N],f[N],size[N],st[N],en[N],dfn,ed;
void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void init(){ memset(g,dfn=ed=0,sizeof(g));memset(v,0,sizeof(v));memset(nxt,0,sizeof(nxt));memset(son,-1,sizeof(son));
}
void dfs(int x){size[x]=1;for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){f[v[i]]=x,d[v[i]]=d[x]+1;dfs(v[i]),size[x]+=size[v[i]];if(size[v[i]]>size[son[x]])son[x]=v[i];}
}
void dfs2(int x,int y){st[x]=++dfn;top[x]=y;if(son[x])dfs2(son[x],y);for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);en[x]=dfn;
}
struct Node{int l,r;int Max;}Tree[N*3];
void build(int x,int l,int r){Tree[x].l=l;Tree[x].r=r;Tree[x].Max=0;if(l==r)return;int mid=(l+r)>>1;build(x<<1,l,mid);build((x<<1)|1,mid+1,r);
}
void up(int x){Tree[x].Max=max(Tree[x<<1].Max,Tree[(x<<1)|1].Max);}
void update(int x,int k,int val){if(Tree[x].l==k&&Tree[x].r==k){Tree[x].Max=val;return;}int mid=(Tree[x].l+Tree[x].r)>>1;if(k<=mid)update(x<<1,k,val);else update((x<<1)|1,k,val);up(x);
}
int query(int x,int l,int r){if(Tree[x].l==l&&Tree[x].r==r)return Tree[x].Max;int mid=(Tree[x].l+Tree[x].r)>>1;if(r<=mid)return query(x<<1,l,r);else if(l>mid)return query((x<<1)|1,l,r);else return max(query(x<<1,l,mid),query((x<<1)|1,mid+1,r));
}
int find(int x,int y){int tmp=0;for(;top[x]!=top[y];x=f[top[x]]){if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}tmp=max(tmp,query(1,st[top[x]],st[x]));}if(x==y)return tmp;if(d[x]>d[y]){int z=x;x=y;y=z;}return max(tmp,query(1,st[son[x]],st[y]));
}int e[N][3];
int main(int n,int T){scanf("%d",&T);while(T--){init(); scanf("%d",&n);for(int i=0;i<n-1;i++){scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);add(e[i][0],e[i][1]);add(e[i][1],e[i][0]);}dfs(1);dfs2(1,1);build(1,1,dfn);for(int i=0;i<n-1;i++){if(d[e[i][0]]>d[e[i][1]])swap(e[i][0],e[i][1]);update(1,st[e[i][1]],e[i][2]);}char op[10]; int u,w;while(scanf("%s",op)==1){if(op[0]=='D')break;scanf("%d%d",&u,&w);if(op[0]=='Q')printf("%d\n",find(u,w));else update(1,st[e[u-1][1]],w);}}return 0;
}

QTREE2

/*题目大意:给出一棵边权树,要求实现树链求和以及求链上第k个元素题解:边权转点权后用LCT维护,注意求Qkth和sum时区别于点权树的讨论
*/
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int N=300010;
namespace Link_Cut_Tree{vector<int> v[N],w[N];int f[N],son[N][2],tmp[N],size[N],val[N],sum[N]; void init(){memset(val,0,sizeof(val));memset(sum,0,sizeof(sum));memset(f,0,sizeof(f));memset(son,0,sizeof(son));for(int i=1;i<N;i++)size[i]=1,v[i].clear(),w[i].clear();}bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}void up(int x){ sum[x]=val[x]+sum[son[x][0]]+sum[son[x][1]];size[x]=size[son[x][0]]+size[son[x][1]]+1;}void rotate(int x){int y=f[x],w=son[y][1]==x;son[y][w]=son[x][w^1];if(son[x][w^1])f[son[x][w^1]]=y;if(f[y]){int z=f[y];if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;}f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);}void splay(int x){int s=1,i=x,y;tmp[1]=i;while(!isroot(i))tmp[++s]=i=f[i];while(!isroot(x)){y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}rotate(x);}up(x);}void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}// 求边权树的链和int ask(int x,int y){  access(y),y=0;  int ans=0;  while(x){  splay(x);  if(!f[x])return sum[son[x][1]]+sum[y];  son[x][1]=y; up(x);  x=f[y=x];  }  }  void dfs(int x,int fx){for(int i=0;i<v[x].size();i++){int y=v[x][i];if(y==fx)continue;f[y]=x;val[y]=w[x][i];dfs(y,x);}up(x);}int kth(int x,int k){while(size[son[x][0]]+1!=k){if(k<size[son[x][0]]+1)x=son[x][0];else{k-=size[son[x][0]]+1;x=son[x][1];}}return x;}// 求边权树u->v的第k个点int Qkth(int u,int v,int k){access(u),u=0;while(v){splay(v);if(!f[v]){  if(size[son[v][1]]+1==k)return v;  else if(size[son[v][1]]+1>k)return kth(son[v][1],size[son[v][1]]+1-k);  else return kth(u,k-(size[son[v][1]]+1));  }son[v][1]=u;up(v); v=f[u=v]; }}
}
using namespace Link_Cut_Tree;
int T,x,y,z,k,n;
char op[10];
int main(){scanf("%d",&T);while(T--){scanf("%d",&n);  init();  for(int i=1;i<n;i++){  scanf("%d%d%d",&x,&y,&z);  v[x].push_back(y);w[x].push_back(z);v[y].push_back(x);w[y].push_back(z);}dfs(1,0);  while(scanf("%s",op)){  if(op[1]=='O')break;  if(op[0]=='D'){  scanf("%d%d",&x,&y);  printf("%d\n",ask(x,y));  }  else{    scanf("%d%d%d",&x,&y,&k);  printf("%d\n",Qkth(x,y,k));  }  }  }return 0;
}

QTREE3

/*题目大意:给出一棵一开始都是白点的树,要求维护操作:1.将某个点的颜色取反(黑白互换)2.查询1到x的路径上第一个黑色的点题解:LCT维护子树中黑点的数量,对于颜色取反,则直接flap,对于查询操作通过access(x)将1到x这条链取出,splay上查找即可注意是从1到x,所以是makeroot(1),保证1节点的键值最小
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=100010;
namespace Link_Cut_Tree{int f[N],son[N][2],val[N],sum[N],tmp[N];bool rev[N];void init(){memset(f,0,sizeof(f));memset(son,0,sizeof(son));memset(val,0,sizeof(val));memset(rev,0,sizeof(rev));memset(sum,0,sizeof(sum));} bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}void up(int x){sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];}void rotate(int x){int y=f[x],w=son[y][1]==x;son[y][w]=son[x][w^1];if(son[x][w^1])f[son[x][w^1]]=y;if(f[y]){int z=f[y];if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;}f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);}void splay(int x){int s=1,i=x,y;tmp[1]=i;while(!isroot(i))tmp[++s]=i=f[i];while(s)pb(tmp[s--]);while(!isroot(x)){y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}rotate(x);}up(x);}void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}void makeroot(int x){access(x);splay(x);rev1(x);}void link(int x,int y){makeroot(x);f[x]=y;access(x);}int flip(int x){makeroot(x);val[x]^=1;up(x);}// 查询从1->x的第一个黑点int ask(int x){makeroot(1); access(x); splay(x); // splay只保证了x到根节点标记的下传if(!sum[x])return -1;while(x){pb(x); // 因为有makeroot操作,所以需要下传标记if(!sum[son[x][0]]&&val[x]==1)return x;else if(sum[son[x][0]])x=son[x][0];else x=son[x][1];}}
}
using namespace Link_Cut_Tree;
int n,q,x,y;
int main(){while(~scanf("%d%d",&n,&q)){init();for(int i=1;i<n;i++){scanf("%d%d",&x,&y);link(x,y);}while(q--){scanf("%d%d",&x,&y);if(x)printf("%d\n",ask(y));else flip(y);}}return 0;
}

QTREE4

/*题目大意:给出一棵边权树,一开始所有点都是白点,要求维护两种操作:1.颜色取反(黑白互变)2.查询树上最远的两个白点之间的距离题解:我们维护重心树,对于每个重心维护分治层所有白点到其距离,将其保存在对应方向子重心的优先队列中,重心处另外维护一个队列保存该分治层每个子重心所产生的最大答案,即最大值加次大值,那么每个重心处产生的最大答案的最值就是答案,考虑修改问题,等价于在处理优先队列的删除问题,对于每个需要删除操作的优先队列,我们额外创建一个优先队列将删除元素加入其中,当两个队列top元素相同时同时删去即可。
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N=200010;
const int INF=0x3f3f3f3f;
int tot,g[N],nxt[N<<1],v[N<<1],w[N<<1];
int TOT,G[N],NXT[N*20],V[N*20],W[N*20];
void init(){memset(g,-1,sizeof(g));tot=0;memset(G,-1,sizeof(G));TOT=0;
}
void add_edge(int x,int y,int z){v[tot]=y,w[tot]=z,nxt[tot]=g[x],g[x]=tot++;}
void ADD_EDGE(int x,int y,int z){V[TOT]=y,W[TOT]=z,NXT[TOT]=G[x],G[x]=TOT++;}
int sum,root,size[N],dp[N],vis[N];
void getroot(int x,int fx){size[x]=1; dp[x]=0;for(int i=g[x];~i;i=nxt[i]){if(!vis[v[i]]&&v[i]!=fx){getroot(v[i],x);size[x]+=size[v[i]];dp[x]=max(dp[x],size[v[i]]);}}dp[x]=max(dp[x],sum-size[x]);if(dp[x]<dp[root])root=x;
}
struct Que{priority_queue<int> Q,D;void clear(){while(!Q.empty())Q.pop();while(!D.empty())D.pop();}void add(int x){Q.push(x);}void del(int x){D.push(x);}int top(){for(;;){if(Q.empty())return -INF;else if(!D.empty()&&Q.top()==D.top())Q.pop(),D.pop();else return Q.top();}}int toptwo(){int x=top();del(x);int y=top();add(x);if(y==-INF)return x==-INF?x:0;return max(x+y,0);}
}P[N],Q[N],ans;
int dis[N],col[N];
void getdis(int rt,int x,int fx){Q[rt].add(dis[x]);for(int i=g[x];~i;i=nxt[i]){if(v[i]==fx||vis[v[i]])continue;dis[v[i]]=dis[x]+w[i];getdis(rt,v[i],x);}
}
void getdeep(int rt,int x,int fx){ADD_EDGE(x,rt,dis[x]);for(int i=g[x];~i;i=nxt[i]){if(v[i]==fx||vis[v[i]])continue;dis[v[i]]=dis[x]+w[i];getdeep(rt,v[i],x);}
}
int belong[N];
void build(int x,int fx,int from,int d){belong[x]=fx; dis[x]=0; getdeep(x,x,fx); P[x].add(0);if(fx){dis[from]=d;getdis(x,from,fx);P[fx].add(Q[x].top());}vis[x]=1;for(int i=g[x];~i;i=nxt[i])if(!vis[v[i]]){root=0; sum=size[v[i]];getroot(v[i],x);build(root,x,v[i],w[i]);}ans.add(P[x].toptwo());
}
void change(int rt){int a=P[rt].toptwo();if(col[rt])P[rt].add(0);else P[rt].del(0);int b=P[rt].toptwo();if(a!=b)ans.del(a),ans.add(b);int x=rt;for(int i=G[rt];~NXT[i];i=NXT[i]){int y=V[NXT[i]],len=W[NXT[i]];x=V[i];a=Q[x].top();if(col[rt])Q[x].add(len);else Q[x].del(len);b=Q[x].top();if(a!=b){int c=P[y].toptwo();P[y].del(a),P[y].add(b);int d=P[y].toptwo();if(c!=d)ans.del(c),ans.add(d);}}
}
int n,m,a,b,c,x;
char op[10];
int main(){scanf("%d",&n); init();for(int i=1;i<=n;i++)col[i]=1;for(int i=1;i<n;i++){scanf("%d%d%d",&a,&b,&c);add_edge(a,b,c);add_edge(b,a,c);}memset(vis,0,sizeof(vis));dp[root=0]=sum=n;getroot(1,0);build(root,0,0,0);scanf("%d",&m);int cnt=n;while(m--){scanf("%s",op);if(op[0]=='A'){if(cnt)printf("%d\n",ans.top());else puts("They have disappeared.");}else{scanf("%d",&x);col[x]^=1;if(col[x])cnt++;else cnt--;change(x);}}return 0;
}

QTREE5

/*题目大意:给出一棵树,边权均为1,一开始所有点都是白点,要求维护两种操作:1.颜色取反(黑白互变)2.查询树上某点距离最近的白点与其距离题解:我们维护重心树,对于每个重心维护分治层所有白点到其距离,将其保存在对应方向子重心的优先队列中,重心处另外维护一个队列表示每个子重心的最小答案,考虑修改问题,等价于在处理优先队列的删除问题,对于每个需要删除操作的优先队列,我们额外创建一个优先队列将删除元素加入其中,当两个队列top元素相同时同时删去即可。对于查询操作,我们沿着重心链用经过每个重心的最优值更新答案
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N=200010;
const int INF=0x3f3f3f3f;
int tot,g[N],nxt[N<<1],v[N<<1],w[N<<1];
int TOT,G[N],NXT[N*20],V[N*20],W[N*20];
void init(){memset(g,-1,sizeof(g));tot=0;memset(G,-1,sizeof(G));TOT=0;
}
void add_edge(int x,int y,int z){v[tot]=y,w[tot]=z,nxt[tot]=g[x],g[x]=tot++;}
void ADD_EDGE(int x,int y,int z){V[TOT]=y,W[TOT]=z,NXT[TOT]=G[x],G[x]=TOT++;}
int sum,root,size[N],dp[N],vis[N];
void getroot(int x,int fx){size[x]=1; dp[x]=0;for(int i=g[x];~i;i=nxt[i]){if(!vis[v[i]]&&v[i]!=fx){getroot(v[i],x);size[x]+=size[v[i]];dp[x]=max(dp[x],size[v[i]]);}}dp[x]=max(dp[x],sum-size[x]);if(dp[x]<dp[root])root=x;
}
struct Que{priority_queue<int,vector<int>,greater<int> > Q,D;void clear(){while(!Q.empty())Q.pop();while(!D.empty())D.pop();}void add(int x){Q.push(x);}void del(int x){D.push(x);}int top(){for(;;){if(Q.empty())return INF;else if(!D.empty()&&Q.top()==D.top())Q.pop(),D.pop();else return Q.top();}}
}P[N],Q[N];
int dis[N],col[N];
void getdis(int rt,int x,int fx){for(int i=g[x];~i;i=nxt[i]){if(v[i]==fx||vis[v[i]])continue;dis[v[i]]=dis[x]+w[i];getdis(rt,v[i],x);}
}
void getdeep(int rt,int x,int fx){ADD_EDGE(x,rt,dis[x]);for(int i=g[x];~i;i=nxt[i]){if(v[i]==fx||vis[v[i]])continue;dis[v[i]]=dis[x]+w[i];getdeep(rt,v[i],x);}
}
int belong[N];
void build(int x,int fx,int from,int d){belong[x]=fx; dis[x]=0; getdeep(x,x,fx); if(fx){dis[from]=d;getdis(x,from,fx);}vis[x]=1;for(int i=g[x];~i;i=nxt[i])if(!vis[v[i]]){root=0; sum=size[v[i]];getroot(v[i],x);build(root,x,v[i],w[i]);}
}
void change(int rt){if(col[rt])P[rt].add(0);else P[rt].del(0);int x=rt;for(int i=G[rt];~NXT[i];i=NXT[i]){int y=V[NXT[i]],len=W[NXT[i]];x=V[i];int a=Q[x].top();if(col[rt])Q[x].add(len);else Q[x].del(len);int b=Q[x].top();if(a!=b)P[y].del(a),P[y].add(b);}
}
int ask(int rt){int ans=INF;for(int i=G[rt];~i;i=NXT[i]){int x=V[i],len=W[i];int a=P[x].top();if(a+len<ans)ans=a+len;}return ans;
}
int n,m,a,b,c,x,op;
int main(){scanf("%d",&n); init();for(int i=1;i<=n;i++)col[i]=0;for(int i=1;i<n;i++){scanf("%d%d",&a,&b);add_edge(a,b,1);add_edge(b,a,1);}memset(vis,0,sizeof(vis));dp[root=0]=sum=n;getroot(1,0);build(root,0,0,0);scanf("%d",&m);int cnt=0;while(m--){scanf("%d%d",&op,&x);if(op==1){if(cnt)printf("%d\n",ask(x));else puts("-1");}else{col[x]^=1;if(col[x])cnt++;else cnt--;change(x);}}return 0;
}

QTREE6

/*题目大意:给出一棵树,一开始树上点均为黑色,要求维护操作1.翻转某点的颜色(黑白互换),2.查询某个点所在连通块(颜色相同则连通)大小题解:我们分别维护黑点LCT和白点LCT,当一个点从黑变白时,将其从黑点LCT中与父节点断开,然后在白点LCT中与父节点相连,这样我们就保证了每个连通块在LCT中只有父节点是不同色的而其余一定是连通的。考虑用LCT维护子树信息,根据在LCT上的连接情况,我们将点的儿子分为实儿子和虚儿子实儿子是原本树结构上相连的点,实儿子的子树为实子树,虚儿子的子树为虚子树x的LCT子树的信息和等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去同时在link x到y的时候,我们需要对y进行access再splay这样就只会对y的虚子树信息和LCT子树信息产生影响,而不会影响到y的祖先节点
*/
#include <cstdio>
#include <algorithm>
#include <set>
const int N=100010;
using namespace std;
int n,m,i,k,x,y,c[N],fa[N],g[N],v[N<<1],nxt[N<<1],ed;
struct LCT{int son[N][2],f[N],sum[N],s[N];bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}void up(int x){sum[x]=1+sum[son[x][0]]+sum[son[x][1]]+s[x];}void rotate(int x){int y=f[x],w=son[y][1]==x;son[y][w]=son[x][w^1];if(son[x][w^1])f[son[x][w^1]]=y;if(f[y]){int z=f[y];if(son[z][0]==y)son[z][0]=x;if(son[z][1]==y)son[z][1]=x;}f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);}void splay(int x){while(!isroot(x)){int y=f[x];if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}rotate(x);}up(x);}void access(int x){for(int y=0;x;y=x,x=f[x]){splay(x);if(son[x][1])s[x]+=sum[son[x][1]];if(son[x][1]=y)s[x]-=sum[y];up(x);}}int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}void link(int x){access(fa[x]);splay(fa[x]);splay(x);son[fa[x]][1]=x;up(f[x]=fa[x]);}void cut(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}int ask(int x){splay(x=root(x));return sum[son[x][1]];}
}T[2];
void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){fa[v[i]]=T[c[v[i]]].f[v[i]]=x;dfs(v[i]);T[c[v[i]]].s[x]+=T[c[v[i]]].sum[v[i]];}T[0].up(x),T[1].up(x);
}
void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
}
int main(){read(n);for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);for(i=1;i<=n;i++)c[i]=0;fa[1]=T[c[1]].f[1]=n+1;dfs(1);T[c[1]].s[n+1]+=T[c[1]].sum[1];read(m);while(m--){read(k);read(x);if(!k)printf("%d\n",T[c[x]].ask(x));else T[c[x]].cut(x),T[c[x]^=1].link(x);}return 0;
}

QTREE7

/*题目大意:给出一棵树,树上每个点为黑色或者白色,每个点有个点权,我们认为树上颜色相同并通过边连接的块为连通块要求维护操作:0.查询x所在连通块中权值最大的点1.翻转某点的颜色(黑白互换)2.改变某点的权值题解:我们分别维护黑点LCT和白点LCT,当一个点从黑变白时,将其从黑点LCT中与父节点断开,然后在白点LCT中与父节点相连,这样我们就保证了每个连通块在LCT中只有父节点是不同色的而其余一定是连通的。考虑用LCT维护子树信息,根据在LCT上的连接情况,我们将点的儿子分为实儿子和虚儿子实儿子是原本树结构上相连的点,实儿子的子树为实子树,虚儿子的子树为虚子树x的LCT子树的信息和等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去同时在link x到y的时候,我们需要对y进行access再splay这样就只会对y的虚子树信息和LCT子树信息产生影响,而不会影响到y的祖先节点因为要维护的信息是极值,因此我们要用multiset来维护虚子树信息
*/
#include <cstdio>
#include <algorithm>
#include <ctype.h>
#include <set>
const int N=100010;
using namespace std;
int n,m,k,x,y,c[N],fa[N],g[N],v[N<<1],nxt[N<<1],ed;
struct LCT{int son[N][2],f[N],val[N],mx[N];multiset<int> s[N];bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}void up(int x){mx[x]=val[x];if(s[x].size())mx[x]=max(mx[x],*s[x].rbegin());if(son[x][0])mx[x]=max(mx[x],mx[son[x][0]]);if(son[x][1])mx[x]=max(mx[x],mx[son[x][1]]);}void rotate(int x){int y=f[x],w=son[y][1]==x;son[y][w]=son[x][w^1];if(son[x][w^1])f[son[x][w^1]]=y;if(f[y]){int z=f[y];if(son[z][0]==y)son[z][0]=x;if(son[z][1]==y)son[z][1]=x;}f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);}void splay(int x){while(!isroot(x)){int y=f[x];if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}rotate(x);}up(x);}void access(int x){for(int y=0;x;y=x,x=f[x]){splay(x);if(son[x][1])s[x].insert(mx[son[x][1]]);if(son[x][1]=y)s[x].erase(s[x].find(mx[y]));up(x);}}int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}void link(int x){access(fa[x]);splay(fa[x]);splay(x);son[fa[x]][1]=x;up(f[x]=fa[x]);}void cut(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}int ask(int x){int t=c[x]; splay(x=root(x));return t==c[x]?mx[x]:mx[son[x][1]];}void modify(int x,int v){access(x),splay(x),val[x]=v,up(x);}
}T[2];
void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){fa[v[i]]=T[c[v[i]]].f[v[i]]=x;dfs(v[i]);T[c[v[i]]].s[x].insert(T[c[v[i]]].mx[v[i]]);}T[0].up(x),T[1].up(x);
}
void read(int &x){  char ch;for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());  int t;if(ch=='-')t=-1,ch=getchar();else t=1;  for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';  x=x*t;
}
int main(){read(n);for(int i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);for(int i=1;i<=n;i++)read(c[i]);  for(int i=1;i<=n;i++)read(T[0].val[i]),T[1].val[i]=T[0].val[i];  dfs(1); read(m);while(m--){read(k);read(x);if(k==0)printf("%d\n",T[c[x]].ask(x));else if(k==1)T[c[x]].cut(x),T[c[x]^=1].link(x);else if(k==2)read(y),T[0].modify(x,y),T[1].modify(x,y);}return 0;
}

转载于:https://www.cnblogs.com/forever97/p/QTREE.html

SPOJ QTREE相关推荐

  1. SPOJ QTree【树链剖分】

    一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...

  2. 【高级数据结构】[SPOJ QTREE]树链剖分/动态树各一模板

    题目: 树链剖分: #include<cstdio> #include<cstring> #include<algorithm> using namespace s ...

  3. SPOJ - QTREE Query on a tree(树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一棵由n个点组成的树,再给出数个操作,每次操作分为下列几种类型: QUERY x y:询问点x-点y这条路径上的所有边权的最大值 CHANGE x y:将第x条边的权 ...

  4. [kuangbin]各种各样的题单

    [kuangbin]各种各样的题单 专题1 简单搜索 POJ 1321 POJ 2251 POJ 3278 POJ 3279 POJ 1426 POJ 3126 POJ 3087 POJ 3414 F ...

  5. 树链剖分入门——[kuangbin]树链剖分

    树链剖分的本质就是将一棵树拆分成一段一段连续的区间,然后放在一起就可以用一棵单独的线段树处理区间问题,只需要将树上节点和线段树节点的对应关系求好就可以很方便的互相转换,而树上两点之间路径的相关问题就可 ...

  6. SPOJ 375. Query on a tree (树链剖分)

    题目链接: http://www.spoj.com/problems/QTREE/ 375. Query on a tree Problem code: QTREE You are given a t ...

  7. spoj 375 Query on a tree (树链剖分)

    题目链接: http://www.spoj.com/problems/QTREE/ 题意: 给一颗树,每条边有一个权值.有两种操作: 1.修改某条边的值: 2.询问a.b两点路径上边权的最大值. 分析 ...

  8. SPOJ 375 Query on a tree(线段树维护树链剖分)

    题目链接:http://www.spoj.com/problems/QTREE/ 题意:给出一个树,两种操作:(1)修改某条边的权值:(2)询问某两个顶点之间边的最大值. 思路:树的路径剖分和线段树维 ...

  9. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB Submit: 7669  Solved: 1894 [Sub ...

最新文章

  1. 跟阿里云技术专家阙寒一起深度了解视频直播CDN技术
  2. 160523、Oracle建立表空间和用户
  3. 一个html5流星雨源码
  4. Vue自定义组件——非单文件组件
  5. React Native Keyboard使用详解
  6. python与mongodb更新_Python对MongoDB增删改查
  7. 使用网络调试助手连接EMQ服务器
  8. android 网易音乐sdk,Netease Music SDK 开发文档
  9. Java 下载 Excel模板
  10. aspcms系统加密后https后台无法登录解决办法
  11. P5.js创意自画像编程
  12. 【Verilog】马里奥小游戏的FPGA实现
  13. 读《终身学习》 哈佛毕业后的六堂课,整理总结
  14. python全栈工程师薪水_Python工程师薪资刷出新高度,有望成为世界上最流行的编程语言...
  15. iphone的Safari浏览器中HTML5上传图片方向问题解决方法
  16. windows无法连接到打印机?三个方法连接打印机(Win10系统)
  17. java缩放图片_java 图片缩放(2)
  18. OTA市场寡头竞争态势严峻,同程艺龙赴港IPO能否改变现状?
  19. Dropout技术之随机神经元与随机深度
  20. 主机连接wifi时,虚拟机VMware如何连接网络

热门文章

  1. 帆软报表在已经搭载服务器上开发_史上最全企业数据产品选型对比(含数仓、报表、BI、中台、数据治理)...
  2. php权限在哪设置,php如何设置管理员权限
  3. java util.function.BiConsumer
  4. Python type创建类
  5. Pandas to_datetime
  6. MySQL Miscellaneous Functions(ip uuid方法)
  7. linux rename
  8. 数据结构之基于Java的顺序队列实现
  9. 一图流“系列——Ruby vSphere Console命令脑图
  10. Java基础学习总结(182)——Java 日志记录实践总结