Query on a tree V VI VII [LCT]

QTREE5

Operation: reverse the color of a point, query the nearest white point of a point

We maintain the distance from the shallowest node to the nearest white point (lsum) and the distance from the deepest node to its nearest white point (rsum) in Splay.

So the answer to query x is obviously Accss (x), splay (x), X - > Rsum.

Consider how to push up

Minson is a virtual subtree answer, maintained with a set

#include<bits/stdc++.h>
#define N 100050
using namespace std;
int read(){
	int cnt = 0; char ch = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt;
}
const int inf = 0x3fffffff;
vector<int> v[N];
int n, m, col[N];
int ch[N][2], fa[N], siz[N], lsum[N], rsum[N];
multiset <int> S[N]; 
void dfs(int u, int f){
	for(int i=0; i<v[u].size(); i++){
		int t = v[u][i]; if(t == f) continue;
		fa[t] = u; S[u].insert(inf + 1); dfs(t, u);
	} 
}
#define ls ch[x][0]
#define rs ch[x][1]
bool isRoot(int x){ return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
int Top(int x){ if(S[x].empty()) return inf; return *S[x].begin();}
void Pushup(int x){
	if(!x) return; lsum[x] = rsum[x] = inf;
	siz[x] = siz[ls] + siz[rs] + 1;
	lsum[x] = min(lsum[ls], siz[ls] + min(col[x] ? 0 : inf, min(Top(x), lsum[rs] + 1)));
	rsum[x] = min(rsum[rs], siz[rs] + min(col[x] ? 0 : inf, min(Top(x), rsum[ls] + 1)));
}
void rotate(int x){
	int y = fa[x], z = fa[y], k = ch[y][1] == x;
	if(!isRoot(y)) ch[z][ch[z][1] == y] = x; fa[x] = z;
	ch[y][k] = ch[x][k^1]; fa[ch[x][k^1]] = y;
	ch[x][k^1] = y; fa[y] = x; Pushup(y); Pushup(x);
}
void Splay(int x){
	while(!isRoot(x)){
		int y = fa[x], z = fa[y];
		if(!isRoot(y)) rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y);
		rotate(x);
	}
}
void Access(int x){
	for(int y = 0; x; y = x, x = fa[x]){
		Splay(x); 
		if(rs) S[x].insert(lsum[rs] + 1);
		rs = y;
		if(rs) S[x].erase(S[x].find(lsum[rs] + 1));
		Pushup(x);
	}
}
int main(){
	n = read(); lsum[0] = rsum[0] = inf;
	for(int i=1; i<n; i++){
		int x = read(), y = read();	
		v[x].push_back(y); v[y].push_back(x); 
	} dfs(1, 0);
	m = read();
	while(m--){
		int op = read(), x = read();
		if(op == 0){ Access(x); Splay(x); col[x] ^= 1; Pushup(x);}
		if(op == 1){ Access(x); Splay(x); printf("%d\n", (rsum[x] == inf) ? -1 : rsum[x]);}
	} return 0;
}

QTREE6 

Operation: reverse color, query the size of connected blocks of the same color

First, open two LCT s, reverse color is equivalent to violent Cut and violent Link on one side

We consider only Cut x and its fa, also Link x and its fa. Such a connected block only has the possibility that rt is different from its color, so it's better to judge specially.

And then there's the Siz that maintains the virtual subtree.

#include<bits/stdc++.h>
#define N 1000050
using namespace std;
int read(){
	int cnt = 0; char ch = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt;
}
int first[N], nxt[N], to[N], tot;
void add(int x, int y){ nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
int n, m, col[N];
struct LCT{
	struct Node{ int ch[2], fa, siz; } t[N];
	int si[N];
	#define ls t[x].ch[0] 
	#define rs t[x].ch[1]
	bool isRoot(int x){ int fa = t[x].fa; return t[fa].ch[0] != x && t[fa].ch[1] != x; }
	void Pushup(int x){ t[x].siz = t[ls].siz + t[rs].siz + si[x] + 1;}
	void rotate(int x){
		int y = t[x].fa, z = t[y].fa, k = t[y].ch[1] == x;
		if(!isRoot(y)) t[z].ch[t[z].ch[1] == y] = x; t[x].fa = z;
		t[y].ch[k] = t[x].ch[k^1]; t[t[x].ch[k^1]].fa = y;
		t[x].ch[k^1] = y; t[y].fa = x; Pushup(y); Pushup(x);
	}
	void Splay(int x){
		while(!isRoot(x)){
			int y = t[x].fa, z = t[y].fa;
			if(!isRoot(y)) rotate((t[y].ch[0] == x) ^ (t[z].ch[0] == y) ? x : y);
			rotate(x);
		} Pushup(x);
	}
	void Access(int x){
		for(int y=0; x; y=x, x=t[x].fa){ 
			Splay(x);
			si[x] += t[rs].siz;
			rs = y;
			si[x] -= t[rs].siz;
			Pushup(x);
		} 
	}
	void Link(int x, int y){ 
		if(!y) return;
		Access(y); Splay(y); Splay(x); t[x].fa = y; si[y] += t[x].siz; Pushup(y); 
	}
	void Cut(int x, int y){
		if(!y) return;
		Access(x); Splay(x); t[ls].fa = 0; ls = 0; Pushup(x);
	}
	int Findroot(int x){
		Access(x); Splay(x);
		while(ls) x = ls; Splay(x);
		return x; 
	}
	int Quary(int x){
		int c = col[x]; x = Findroot(x);
		return col[x] == c ? t[x].siz : t[rs].siz;
	}
}lct[2]; 
int fa[N];
void dfs(int u, int f){
	for(int i=first[u];i;i=nxt[i]){
		int t = to[i]; if(t == f) continue;
		fa[t] = u; lct[0].Link(t, u); dfs(t, u);
	}
}
int main(){
	n = read();	
	for(int i=1; i<n; i++){
		int x = read(), y = read();
		add(x, y); add(y, x);
	} dfs(1, 0); m = read();
	while(m--){
		int op = read(), x = read();
		if(op == 0) printf("%d\n", lct[col[x]].Quary(x));
		if(op == 1){ lct[col[x]].Cut(x, fa[x]); col[x] ^= 1; lct[col[x]].Link(x, fa[x]);}
	} return 0;
}

QTREE7 

Similar to the previous question, maintain the maximum value of homochromatic connected block, multiset is OK.

#include<bits/stdc++.h>
#define N 200050
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
int first[N], nxt[N], to[N], tot;
void add(int x, int y){nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
int n, m, col[N], f[N], w[N];
struct Node{
	int ch[N][2], fa[N], Max[N];
	multiset<int> S[N];
	bool isRoot(int x){ return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
	void Pushup(int x){
		Max[x] = max(w[x], max(Max[ch[x][0]], Max[ch[x][1]]));
		if(S[x].size()) Max[x] = max(Max[x], *S[x].rbegin());
	}
	void rotate(int x){
		int y = fa[x], z = fa[y], k = ch[y][1] == x;
		if(!isRoot(y)) ch[z][ch[z][1] == y] = x; fa[x] = z;
		ch[y][k] = ch[x][k^1]; fa[ch[x][k^1]] = y;
		ch[x][k^1] = y; fa[y] = x; Pushup(y); Pushup(x);
	}
	void Splay(int x){
		while(!isRoot(x)){
			int y = fa[x], z = fa[y];
			if(!isRoot(y)) rotate((ch[y][1]==x) ^ (ch[z][1]==y) ? x : y);
			rotate(x); 
		} Pushup(x);
	}
	void Access(int x){
		for(int y = 0; x; y = x, x = fa[x]){
			Splay(x); 
			if(ch[x][1]) S[x].insert(Max[ch[x][1]]);
			ch[x][1] = y; 
			if(ch[x][1]) S[x].erase(Max[ch[x][1]]);
			Pushup(x);
		}
	}
	int Findroot(int x){
		Access(x); Splay(x); while(ch[x][0]) x = ch[x][0]; Splay(x); return x;
	}
	void Link(int x, int y){
		if(!y) return;
		Access(y); Splay(y); Splay(x);
		fa[x] = y; S[y].insert(Max[x]); Pushup(y);
	}
	void Cut(int x, int y){
		if(!y) return;
		Access(x); Splay(x); fa[ch[x][0]] = 0; ch[x][0] = 0; Pushup(x);
	}
	int Quary(int x){
		int c = col[x]; x = Findroot(x);
		return col[x] == c ? Max[x] : Max[ch[x][1]];
	}
	void Modify(int x){
		Access(x); Splay(x); w[x] = read(); Pushup(x);
	}
}T[2];
void dfs(int u, int ff){
	for(int i=first[u];i;i=nxt[i]){
		int t = to[i]; if(t == ff) continue;
		T[col[t]].Link(t, u); f[t] = u; dfs(t, u); 
	}
}
int main(){
	n = read();
	for(int i=1; i<n; i++){
		int x = read(), y = read();
		add(x, y); add(y, x);
	} 
	for(int i=1; i<=n; i++) col[i] = read();
	for(int i=1; i<=n; i++) w[i] = read();
	T[0].Max[0] = T[1].Max[0] = -2e9;
	dfs(1, 0); m = read();
	while(m--){
		int op = read(), u = read();
		if(op == 0) printf("%d\n", T[col[u]].Quary(u));
		if(op == 1){ T[col[u]].Cut(u, f[u]); col[u] ^= 1; T[col[u]].Link(u, f[u]);}
		if(op == 2){ T[col[u]].Modify(u);}
	} return 0;
}

 

Posted by BoukeBuffel on Sat, 02 Nov 2019 01:57:53 -0700