zoukankan      html  css  js  c++  java
  • [CF1017G]The Tree[树链剖分+线段树]

    题意

    给一棵一开始 (n) 个点全是白色的树,以 (1) 为根,支持三种操作:

    1.将某一个点变黑,如果已经是黑色则该操作对所有儿子生效。
    2.将一棵子树改成白色。
    3.询问某个点的颜色。

    (nleq 10^5)

    分析

    • 唯一棘手的问题是操作1,我们很难正面解决这个问题。

    • 考虑点 (u) 到根的路径,只有在这些点上的操作才可能影响 (u) 的颜色。
      (u) 变黑的那次操作一定是先选定一个 (u) 的祖先,然后祖先到 (u) 的路径上所有的点都已经是黑色。

    • 先将所有点都标记成 (-1) ,表示要将其变黑需要一步,1操作就在对应节点+1。
      所以如果一个点是黑色当且仅当他到根路径上存在一个后缀和 (geq 0)

    • 操作2在将子树变白之后还要考虑子树祖先的影响,可以理解成之前下放的标记废掉了,子树的根节点减去 在根节点查询到的后缀最大值+1 即可。之后如果子树内的点查询时的答案在子树祖先上,那一部分贡献就被删除了。

    • 有没有可能子树的祖先信息修改了,而当前点开始抵消的部分没有撤销?因为覆盖都是子树修改,如果祖先改了撤销信息也没有了,所以不用考虑。

    • 总时间复杂度为 (O(nlog^2n))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    #define pb push_back
    inline int gi() {
        int x = 0,f = 1;
        char ch = getchar();
        while(!isdigit(ch)) {
            if(ch == '-') f = -1;
            ch = getchar();
        }
        while(isdigit(ch)) {
            x = (x << 3) + (x << 1) + ch - 48;
            ch = getchar();
        }
        return x * f;
    }
    template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
    template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
    const int N = 1e5 + 7, inf = 0x3f3f3f3f;
    int n, q, edc, tim;
    int head[N], fa[N], zson[N], son[N], top[N], in[N], out[N];
    struct edge {
    	int lst, to;
    	edge(){}edge(int lst, int to):lst(lst), to(to){}
    }e[N*2];
    void Add(int a, int b) {
    	e[++edc] = edge(head[a], b), head[a] = edc;
    	e[++edc] = edge(head[b], a), head[b] = edc;
    }
    void dfs1(int u) {
    	son[u] = 1;
    	go(u)if(v ^ fa[u]) {
    		fa[v] = u, dfs1(v);
    		son[u] += son[v];
    		if(son[v] > son[zson[u]]) zson[u] = v;
    	}
    }
    void dfs2(int u,int from) {
    	in[u] = ++tim; top[u] = from;
    	if(zson[u]) dfs2(zson[u], from);
    	go(u)if(v ^ fa[u] && v ^ zson[u]) 
    		dfs2(v, v);
    	out[u] = tim;
    }
    int setv[N << 2];
    #define Ls o << 1
    #define Rs o << 1 | 1
    struct data {
    	int mx,s;
    	data(){mx = -inf;}data(int mx, int s):mx(mx), s(s) {}
    	data operator +(const data &b) const {
    		return data(max(b.mx, mx + b.s), s + b.s);
    	}
    }t[N << 2];
    void md(int l, int r, int o) {
    	setv[o] = 1;
    	t[o].mx = -1, t[o].s = -(r - l + 1);
    }
    void pushdown(int l, int r, int o) {
    	if(!setv[o]) return;
    	int mid = l + r >> 1;
    	md(l, mid, Ls);
    	md(mid + 1, r, Rs);
    	setv[o] = 0;
    }
    void pushup(int o) {
    	t[o] = t[Ls] + t[Rs];
    }
    void build(int l, int r, int o) {
    	if(l == r) {
    		t[o].mx = t[o].s = -1;
    		return;
    	}int mid = l + r >> 1;
    	build(l, mid, Ls);
    	build(mid + 1, r, Rs);
    	pushup(o);
    }
    void m1(int p, int l, int r, int o, int v) {
    	if(l == r) {
    		t[o].mx += v, t[o].s += v;
    		return;
    	}
    	pushdown(l, r, o);int mid = l + r >> 1;
    	if(p <= mid) m1(p, l, mid, Ls, v);
    	else m1(p, mid + 1, r ,Rs, v);
    	pushup(o);
    }
    void m2(int L, int R, int l, int r, int o) {
    	if(L <= l && r <= R) {
    		md(l, r, o);
    		return;
    	}
    	pushdown(l, r, o);int mid = l + r >> 1;
    	if(L <= mid) m2(L, R, l, mid, Ls);
    	if(R > mid)  m2(L, R, mid + 1, r, Rs);
    	pushup(o);
    }
    data query(int L, int R, int l, int r, int o) {
    	if(L <= l && r <= R) return t[o];
    	pushdown(l, r, o); int mid = l + r >> 1;
    	if(R <= mid)  return query(L, R, l, mid, Ls);
    	if(L > mid) return query(L, R, mid + 1, r, Rs);
    	return query(L, R, l, mid, Ls) + query(L, R, mid + 1, r, Rs);
    }
    int qry(int u) {
    	data res(-inf, 0);
    	for(; u; u = fa[top[u]]) {
    		res = query(in[top[u]], in[u], 1, n, 1) + res;
    	}
    	return res.mx;
    }
    int main() {
    	n = gi(), q = gi();
    	rep(i, 2, n) Add(gi(), i);
    	dfs1(1); dfs2(1, 1);
    	build(1, n, 1);
    	while(q--) {
    		int opt = gi(), u = gi();
    		if(opt == 1) {
    			m1(in[u], 1, n, 1, 1);
    		}else if(opt == 2){
    			int t = qry(u);
    			m1(in[u], 1, n, 1, -(t + 1));
    			if(in[u] < out[u])
    			m2(in[u] + 1, out[u], 1, n, 1);
    		}else {
    			int t = qry(u);
    			puts(t >= 0 ? "black" : "white");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Yield Usage Understanding
    Deadclock on calling async methond
    How to generate file name according to datetime in bat command
    Run Unit API Testing Which Was Distributed To Multiple Test Agents
    druid的关键参数+数据库连接池运行原理
    修改idea打开新窗口的默认配置
    spring boot -thymeleaf-url
    @pathvariable和@RequestParam的区别
    spring boot -thymeleaf-域对象操作
    spring boot -thymeleaf-遍历list和map
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10114382.html
Copyright © 2011-2022 走看看