• 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
    ", St_tree.query(1, 1, n, dfn[y]));
    	}
    }
    int main(){
    	maiin();
    	return 0;
    }
    

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

  • 相关阅读:
    余额宝数据架构阅读
    VS提示This function or variable may be unsafe,The POSIX name for this item is deprecated
    VS中新建QT空项目找不到头文件的问题
    指针
    循环for do while continue break,达夫设备
    GUI程序弹出控制台打印输出信息
    ctime、chrono以及所有和时间有关的内容
    python安装
    文件:fstream,FILE,CFile,filesystem,以及路径目录
    C++异常处理、Dump文件、断言、静态断言、日志文件
  • 原文地址:https://www.cnblogs.com/wsdslll/p/13399767.html
Copyright © 2020-2023  润新知