题解 QTREE7 - Query on a tree VII

题目描述

一棵树,每个点初始有个点权和颜色。

有以下操作:

  1. 询问所有 \(u,v\) 路径上的最大点权,要满足 \(u,v\) 路径上所有点的颜色都相同。

  2. 反转 \(u\) 的颜色。

  3. \(u\) 的点权改成 \(w\)

具体思路

记白色为 \(0\),记黑色为 \(1\)

LCT 维护的参数:

  • \(fa\):表示当前节点的父亲。

  • \(ch_{0/1}\)\(0\) 表示当前节点的左儿子,\(1\) 表示当前节点的右儿子。

  • \(val\):表示当前节点的权值。

  • \(col\):表示当前节点的颜色。

  • \(lmx\):表示以当前节点为根的子树内,从链头(最左端的点)出发最大连通块大小。

  • \(rmx\):表示以当前节点为根的子树内,从链尾(最右端的点)出发最大连通块大小。

  • \(tcol\):表示当前的实链颜色是否相同,都为白色 \(tcol=0\),都为黑色 \(tcol=1\),有不同颜色 \(tcol=2\)

  • \(lcol\):表示当前链头(最左端的点)的颜色。

  • \(rcol\):表示当前链尾(最右端的点)的颜色。

  • \(lmax\):表示以当前节点为根的子树内,从链头(最左端的点)出发最大连通块内的最大值。

  • \(rmax\):表示以当前节点为根的子树内,从链尾(最右端的点)出发最大连通块内的最大值。

  • \(cnt_{0/1}\):表示当前节点的虚儿子的最大 \(0/1\) 连通块大小。

  • \(hfir_{0/1}\):表示当前节点的虚儿子的最大 \(0/1\) 连通块内 \(lmax\) 的最大值。

我们在当前 splay 中需要维护较多信息。

考虑 \(lmx\) 的转移:

  • \(lmx_{x}=lmx_{lc}\),继承左儿子的 \(lmx\)

  • \(lmx_{x}+=cnt_{col_x,x}+1\) \((tcol_{lc} \ne 2,tcol_{lc}=col_x)\),就是链头可以走到 \(x\) 节点时可以加上虚儿子和它自己的贡献。

  • \(lmx_{x}+=lmx_{rc}\) \((tcol_{lc} \ne 2,tcol_{lc}=col_x,col_x=lcol_{rc})\),就是 \(x\) 节点可以走到 \(rc\) 所在子树的链头。

考虑 \(rmx\) 的转移:

  • \(rmx_{x}=rmx_{rc}\),继承右儿子的 \(rmx\)

  • \(rmx_{x}+=cnt_{col_x,x}+1\) \((tcol_{rc} \ne 2,tcol_{rc}=col_x)\),就是链尾可以走到 \(x\) 节点时可以加上虚儿子和它自己的贡献。

  • \(rmx_{x}+=rmx_{lc}\) \((tcol_{rc} \ne 2,tcol_{rc}=col_x,col_x=rcol_{lc})\),就是 \(x\) 节点可以走到 \(lc\) 所在子树的链尾。

考虑 \(lcol\) 的转移:

  • \(lcol_x=col_x\) \((lc=0)\),没有左儿子自己就是链头。

  • \(lcol_x=lcol_lc\) \((lc \ne 0)\),继承左儿子的 \(lcol\)

考虑 \(rcol\) 的转移:

  • \(rcol_x=col_x\) \((rc=0)\),没有右儿子自己就是链尾。

  • \(rcol_x=rcol_rc\) \((rc \ne 0)\),继承右儿子的 \(rcol\)

考虑 \(tcol\) 的转移:

\(tcol_x=\begin{cases} 2 & tcol_{lc}=2 \\ 2 & tcol_rc=2 \\ 2 & tcol_{lc}\ne col_x \\ 2 & tcol_{rc}\ne col_x \\ col_x & otherwise \end{cases}\)

考虑 \(lmax\) 的转移:

  • \(lmax_{x}=lmax_{lc}\),继承左儿子的 \(lmax\)

  • \(lmax_{x}=max(lmax_{x},hfir_{col_x,x},val_x)\) \((tcol_{lc} \ne 2,tcol_{lc}=col_x)\),就是链头可以走到 \(x\) 节点时可以加上虚儿子和它自己的贡献。

  • \(lmax_{x}=max(lmax_{x},lmax_{rc})\) \((tcol_{lc} \ne 2,tcol_{lc}=col_x,col_x=lcol_{rc})\),就是 \(x\) 节点可以走到 \(rc\) 所在子树的链头。

考虑 \(rmax\) 的转移:

  • \(rmax_{x}=rmax_{rc}\),继承右儿子的 \(rmax\)

  • \(rmax_{x}=max(rmax_x,hfir_{col_x,x},val_x)\) \((tcol_{rc} \ne 2,tcol_{rc}=col_x)\),就是链尾可以走到 \(x\) 节点时可以加上虚儿子和它自己的贡献。

  • \(rmax_{x}=max(rmax_x,rmax_{lc})\) \((tcol_{rc} \ne 2,tcol_{rc}=col_x,col_x=rcol_{lc})\),就是 \(x\) 节点可以走到 \(lc\) 所在子树的链尾。

对于虚儿子的贡献部分,我们可以在建边和 access 的时候处理好,由于我们要维护虚儿子 \(lmax\) 的最大值,因此考虑用 multiset。

Code

#include<bits/stdc++.h>
#define fa(x) tr[x].fa
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')f=0;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
    	x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
    return (!f)?-x:x;
}
const int N=2e5+5;
const int inf=0x7fffffff;
multiset<int>h[2][N];
struct trnode{
	int val,col,fa,ch[2];
	int cnt[2],hfir[2];
	int lmx,rmx;
	int tcol,lcol,rcol;
	int lmax,rmax;
}tr[N];
int solve(multiset<int>&s){
	if(s.size())return *s.rbegin();
	else return -inf;
}
void work(int x){
	tr[x].hfir[0]=solve(h[0][x]);
	tr[x].hfir[1]=solve(h[1][x]);
}
bool notroot(int x){
	return lc(fa(x))==x||rc(fa(x))==x;
}
void pushup(int x){
	tr[x].lmx=tr[lc(x)].lmx;
	tr[x].lmax=tr[lc(x)].lmax;
	if((tr[lc(x)].tcol!=2&&tr[lc(x)].tcol==tr[x].col)||!lc(x)){
		tr[x].lmx+=tr[x].cnt[tr[x].col]+1;
		tr[x].lmax=max({tr[x].lmax,tr[x].hfir[tr[x].col],tr[x].val});
		if(tr[x].col==tr[rc(x)].lcol){
			tr[x].lmax=max(tr[x].lmax,tr[rc(x)].lmax);
			tr[x].lmx+=tr[rc(x)].lmx;
		}
	}
	tr[x].rmx=tr[rc(x)].rmx;
	tr[x].rmax=tr[rc(x)].rmax;
	if((tr[rc(x)].tcol!=2&&tr[rc(x)].tcol==tr[x].col)||!rc(x)){
		tr[x].rmx+=tr[x].cnt[tr[x].col]+1;
		tr[x].rmax=max({tr[x].rmax,tr[x].hfir[tr[x].col],tr[x].val});
		if(tr[x].col==tr[lc(x)].rcol){
			tr[x].rmax=max(tr[x].rmax,tr[lc(x)].rmax);
			tr[x].rmx+=tr[lc(x)].rmx;
		}
	}
	if(!lc(x))tr[x].lcol=tr[x].col;
	else tr[x].lcol=tr[lc(x)].lcol;
	if(!rc(x))tr[x].rcol=tr[x].col;
	else tr[x].rcol=tr[rc(x)].rcol;
	if(tr[lc(x)].tcol==2||tr[rc(x)].tcol==2)tr[x].tcol=2;
	else if(lc(x)&&tr[lc(x)].tcol!=tr[x].col)tr[x].tcol=2;
	else if(rc(x)&&tr[rc(x)].tcol!=tr[x].col)tr[x].tcol=2;
	else tr[x].tcol=tr[x].col;
}
void rotate(int x){
	int y=fa(x),z=fa(y);
	int w=(rc(y)==x),v=tr[x].ch[1-w];
	if(notroot(y)){
		tr[z].ch[rc(z)==y]=x;
	}
	fa(x)=z;
	fa(v)=y,tr[y].ch[w]=v;
	fa(y)=x,tr[x].ch[1-w]=y;
	pushup(y),pushup(x);
}
void splay(int x){
	while(notroot(x)){
		int y=fa(x),z=fa(y);
		if(notroot(y)){
			if((rc(z)==y)==(rc(y)==x))
				rotate(y);
			else rotate(x);
		}
		rotate(x);
	}
}
void access(int x){
	for(int y=0;x;y=x,x=fa(x)){
		splay(x);
		if(rc(x)){
			tr[x].cnt[tr[rc(x)].lcol]+=tr[rc(x)].lmx;
			h[tr[rc(x)].lcol][x].insert(tr[rc(x)].lmax);
		}
		if(y){
			tr[x].cnt[tr[y].lcol]-=tr[y].lmx;
			h[tr[y].lcol][x].erase(h[tr[y].lcol][x].find(tr[y].lmax));
		}
		work(x);
		rc(x)=y;
		pushup(x);
	}
}
int query(int x){
	access(x);
	splay(x);
	return tr[x].rmax;
}
void change(int x){
	access(x);
	splay(x);
	tr[x].col^=1;
	pushup(x);
}
void modify(int x,int c){
	access(x);
	splay(x);
	tr[x].val=c;
	pushup(x);
}
struct edge{
	int x,y,pre;
}a[2*N];
int last[N],alen;
void ins(int x,int y){
	a[++alen]=edge{x,y,last[x]};
	last[x]=alen;
}
void dfs(int x,int fa){
	for(int k=last[x];k;k=a[k].pre){
		int y=a[k].y;
		if(y==fa)continue;
		fa(y)=x;
		dfs(y,x);
		tr[x].cnt[tr[y].lcol]+=tr[y].lmx;
		h[tr[y].lcol][x].insert(tr[y].lmax);
	}
	work(x);
	pushup(x);
}
int main(){
	int n;n=read();
	alen=1;memset(last,0,sizeof(last));
	for(int i=1;i<n;i++){
		int x,y;x=read(),y=read();
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++){
		int c;c=read();
		tr[i].col=c;
		tr[i].lmx=tr[i].rmx=1;
		tr[i].lcol=tr[i].rcol=tr[i].tcol=c;
	}
	tr[0].lmax=tr[0].rmax=-inf;
	for(int i=1;i<=n;i++){
		int c;c=read();
		tr[i].val=c;
		tr[i].lmax=tr[i].rmax=c;
	}
	dfs(1,0);
	int m;m=read();
	for(int i=1;i<=m;i++){
		int op,x,c;op=read();
		if(op==0){
			x=read();
			printf("%d\n",query(x));
		}
		if(op==1){
			x=read();
			change(x);
		}
		if(op==2){
			x=read(),c=read();
			modify(x,c);
		}
	}
	return 0;
}
posted @ 2023-10-26 15:57  reclusive2007  阅读(11)  评论(0编辑  收藏  举报