• [bzoj4196][Noi2015]软件包管理器


    题目大意:有一棵树,两个修改

    1. $install;x:$把根节点到$x$软件路径上的值全部变为$1$,并输出修改的节点个数
    2. $uninstall;x:$把$x$以及它的子树的值变为$0$,并输出修改的节点个数

    题解:树链剖分,比较一下修改前后值的变化,即为答案

    卡点:1.边忘记开两倍

    C++ Code:

    #include <cstdio>
    #define maxn 100010
    using namespace std;
    int n, m;
    
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxn << 1];
    void add(int a, int b) {
    	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    }
    
    int dep[maxn], sz[maxn], fa[maxn];
    int dfn[maxn], son[maxn], top[maxn], idx;
    void dfs1(int rt) {
    	sz[rt] = 1;
    	for (int i = head[rt]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (v != fa[rt]) {
    			fa[v] = rt;
    			dep[v] = dep[rt] + 1;
    			dfs1(v);
    			sz[rt] += sz[v];
    			if (!son[rt] || sz[son[rt]] < sz[v]) son[rt] = v;
    		}
    	}
    }
    void dfs2(int rt) {
    	dfn[rt] = ++idx;
    	int v = son[rt];
    	if (v) top[v] = top[rt], dfs2(v);
    	for (int i = head[rt]; i; i = e[i].nxt) {
    		v = e[i].to;
    		if (v != fa[rt] && v != son[rt]) {
    			top[v] = v;
    			dfs2(v);
    		}
    	}
    }
    
    int V[maxn << 2];
    void add(int rt, int l, int r, int L, int R, int op) {
    	if (L <= l && R >= r) {
    		V[rt] = (r - l + 1) * op;
    		return ;
    	}
    	if (V[rt] == r - l + 1) {
    		V[rt << 1] = r - l + 2 >> 1;
    		V[rt << 1 | 1] = r - l + 1 >> 1;
    	}
    	int mid = l + r >> 1;
    	if (L <= mid) add(rt << 1, l, mid, L, R, op);
    	if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, op);
    	V[rt] = V[rt << 1] + V[rt << 1 | 1];
    }
    int ask(int rt, int l, int r, int L, int R) {
    	if (L <= l && R >= r) return V[rt];
    	if (V[rt] == r - l + 1) {
    		V[rt << 1] = r - l + 2 >> 1;
    		V[rt << 1 | 1] = r - l + 1 >> 1;
    	}
    	if (V[rt] == 0) V[rt << 1] = V[rt << 1 | 1] = 0;
    	int mid = l + r >> 1, ans = 0;
    	if (L <= mid) ans = ask(rt << 1, l, mid, L, R);
    	if (R > mid) ans += ask(rt << 1 | 1, mid + 1, r, L, R);
    	return ans;
    }
    
    inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}
    void modify(int x, int y, int num) {
    	while (top[x] != top[y]) {
    		if (dep[top[x]] < dep[top[y]]) swap(x, y);
    		add(1, 1, n, dfn[top[x]], dfn[x], num);
    		x = fa[top[x]];
    	}
    	if (dep[x] > dep[y]) swap(x, y);
    	add(1, 1, n, dfn[x], dfn[y], num);
    }
    int query(int x, int y) {
    	int ans = 0;
    	while (top[x] != top[y]) {
    		if (dep[top[x]] < dep[top[y]]) swap(x, y);
    		ans += ask(1, 1, n, dfn[top[x]], dfn[x]);
    		x = fa[top[x]];
    	}
    	if (dep[x] > dep[y]) swap(x, y);
    	ans += ask(1, 1, n, dfn[x], dfn[y]);
    	return ans;
    }
    
    int root = 1;
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++) {
    		int a;
    		scanf("%d", &a);
    		add(a + root, i + root);
    		add(i + root, a + root);
    	}
    	dep[top[root] = root] = 1;
    	dfs1(root);
    	dfs2(root);
    	scanf("%d", &m);
    	while (m --> 0) {
    		char op[15];
    		int ans, x;
    		scanf("%s%d", op, &x); x += root;
    		if (op[0] == 'i') {
    			ans = query(root, x);
    			modify(root, x, 1);
    			printf("%d
    ", query(root, x) - ans);
    		} else {
    			ans = ask(1, 1, n, dfn[x], dfn[x] + sz[x] - 1);
    			add(1, 1, n, dfn[x], dfn[x] + sz[x] - 1, 0);
    			printf("%d
    ", ans - ask(1, 1, n, dfn[x], dfn[x] + sz[x] - 1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Mongodb常用操作(转载)
    java中对象转换工具类,很好用
    IDEA中配置tomcat出现乱码的解决
    小山博客--面试题答案
    Redis简单配置和使用
    线程的控制和线程池
    进程与线程详细解释
    Quartz .Net(定时框架):
    C#面向对象几组关键字的详解(this,base,dynamic,var,const,readonly,is,as)
    C#设计模式--抽象工厂模式(创建型模式)
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9519699.html
Copyright © 2020-2023  润新知