• [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;
    }
    
  • 相关阅读:
    adb 连接时候不弹出授权对话框【转】
    Android设备adb授权的原理【转】
    JDK-Logger
    使用xpath时出现noDefClass的错误(找不到某个类)
    Netty系列之Netty 服务端创建
    windows 如何查看端口占用情况?
    解决Apache/PHP无法启动的问题
    多个mysql解决方法
    Qt 静态编译后的exe太大, 可以这样压缩.
    烈焰SWF解密
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10114382.html
Copyright © 2020-2023  润新知