CF343D Water Tree

题面
这是一道树剖的裸题
(第一次水紫题有点快乐)
这道题其实就是轻重链剖分的操作拿出来罢了
我们看到这道题区间修改,单点查询
不难想到线段树吧
然后我们可以想到轻重链剖分那道题
我们会发现操作\(1\)就是将\(dfn[x]\)~\(dfn[x]+siz[x]-1\)这段区间都赋值为\(1\)
这样的话我们就可以\(O(log)\)地维护了
然后我们考虑一下操作\(2\)我们发现,跳重链地过程其实就是不断向\(1\)移动的过程
所以我们在每次跳重链的时候,顺便在线段树上修改一下值就好了
操作\(3\)其实就是线段树单点查询
话不多说,直接放代码

#include<bits/stdc++.h>		
const int N = 5e5 + 5;
using namespace std;
int n, m, head[N], cnt, dfn[N], hev[N], dep[N], siz[N], top[N], sum, fa[N];
struct node{
	int u, v, nxt;
}edge[N << 1];
void add(int u, int v){
	edge[++ cnt].u = u;
	edge[cnt].v = v;
	edge[cnt].nxt = head[u];
	head[u] = cnt;
}
struct tree{
	protected:
		#define ls(o) (o << 1)
		#define rs(o) (o << 1 | 1)
		#define mid ((l + r) >> 1)
		int tr[N << 2], laz[N << 2];
		void up(int o){ tr[o] = tr[ls(o)] + tr[rs(o)];}
		void down(int o, int l, int r){
			laz[ls(o)] = laz[rs(o)] = laz[o];
			tr[ls(o)] = laz[o] * (mid - l + 1);
			tr[rs(o)] = laz[o] * (r - mid);
			laz[o] = -1;
		}
		void build(int o, int l, int r){
			if(l == r){ tr[o] = 0; return ;}
			build(ls(o), l, mid); build(rs(o), mid + 1, r);
			up(o);
		}
	public:
		void change(int o, int l, int r, int L, int R, int val){
			if(L <= l && r <= R){
				tr[o] = val * (r - l + 1); laz[o] = val;
				return ;
			}
			if(laz[o] != -1) down(o, l, r);
			if(L <= mid) change(ls(o), l, mid, L, R, val);
			if(R > mid) change(rs(o), mid + 1, r, L, R, val);
			up(o);
		}
		int query(int o, int l, int r, int x){
			if(l == r){ return laz[o];}
			if(laz[o] != -1) down(o, l, r);
			if(x <= mid) return query(ls(o), l, mid, x);
			else return query(rs(o), mid + 1, r, x);
		}
		void cz(int x){ build(1, 1, x);}
}St_tree;
struct Powtree{
	void Ps(int x){
		siz[x] = 1;
		for(int i = head[x]; i; i = edge[i].nxt){
			int to = edge[i].v;
			if(to == fa[x]) continue;
			dep[to] = dep[x] + 1;
			fa[to] = x;
			Ps(to);
			siz[x] += siz[to];
			if(siz[to] > siz[hev[x]]) hev[x] = to;
		}
	}
	void dfs(int x, int topp){
		top[x] = topp;
		dfn[x] = ++ sum;
		if(hev[x]) dfs(hev[x], topp);
		for(int i = head[x]; i; i = edge[i].nxt){
			int to = edge[i].v;
			if(to == fa[x] || to == hev[x]) continue;
			dfs(to, to);
		}
	}
	void cz(){
		dep[1] = 1;
		Ps(1);
		dfs(1, 1);
	}
}Pow_tree;
int read(){
	int op = 0, opp = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){ if(ch == '-') opp = -1; ch = getchar();}
	while(ch <= '9' && ch >= '0'){ op = (op << 1) + (op << 3) + (ch ^ 48); ch = getchar();}
	return op * opp;
}
void Build_tree(){
	Pow_tree.cz();
	St_tree.cz(n);
}
void Jump(int x){
	while(x){
		St_tree.change(1, 1, n, dfn[top[x]], dfn[x], 0);
		x = fa[top[x]];
	}
}
void maiin(){
	n = read();
	for(int i = 1, x, y; i < n; i ++){
		x = read(); y = read();
		add(x, y); add(y, x);
	}
	Build_tree();
	m = read();
	for(int i = 1, x, y; i <= m; i ++){
		x = read(); y = read();
		if(x == 1) St_tree.change(1, 1, n, dfn[y], dfn[y] + siz[y] - 1, 1);
		if(x == 2) Jump(y);
		if(x == 3) printf("%d\n", St_tree.query(1, 1, n, dfn[y]));
	}
}
int main(){
	maiin();
	return 0;
}

这道题有个地方很细节,就是在线段树里,没有标记的时候,\(laz\)会被标记为\(-1\),这样就会防止没有\(0\)的标记,却操作中下放了\(0\)的标记,导致了无故的\(WA\)

posted @ 2020-07-29 21:34  Tethys  阅读(133)  评论(5编辑  收藏  举报