• 洛谷P2146 [NOI2015]软件包管理器


    题目

    树链剖分

    安装操作:

    将1到x的点权统统_覆盖_为1,操作前覆盖一次,操作后覆盖一次。然后分别记录这两次1到x的路径点权和,求他们的差即是答案。

    卸载操作:
    输出x的子树点权值和,然后把x的子树点权统统_覆盖_为0。

    覆盖操作可以用ODT,线段树,线段树的lazy数组初始值要赋为-1,因为有区间赋值为0的操作。

    #include <bits/stdc++.h>
    #define N 1000115
    #define ls l, mid, root << 1
    #define rs mid + 1, r, root << 1 | 1 
    using namespace std;
    int n, m, tot, cnt, lin[N], dep[N], fat[N], siz[N], son[N], top[N], dfn[N], tree[N], lazy[N];
    struct edg {
    	int to, nex;
    }e[N];
    inline void add(int f, int t)
    {
    	e[++cnt].nex = lin[f];
    	e[cnt].to = t;
    	lin[f] = cnt;
    }
    void dfs1(int now, int fa)
    {
    	dep[now] = dep[fa] + 1;
    	fat[now] = fa;
    	siz[now] = 1; 
    	for (int i = lin[now]; i; i = e[i].nex)
    	{
    		int to = e[i].to;
    		if (to == fa) continue;
    		dfs1(to, now);
    		siz[now] += siz[to];
    		if (siz[to] > siz[son[now]])
    			son[now] = to;
    	}
    }
    void dfs2(int now, int tes)
    {
     	top[now] = tes;
     	dfn[now] = ++tot;//dfn是dfs序 
     	if (!son[now]) return; 
     	dfs2(son[now], tes);
     	for (int i = lin[now]; i; i = e[i].nex)
     	{
     		int to = e[i].to;
     		if (to == fat[now] || to == son[now]) continue;
     		dfs2(to, to);
     	}
    }
    inline void pushup(int root)
    {
    	tree[root] = tree[root << 1] + tree[root << 1 | 1];
    }
    inline void pushdown(int l, int r, int root)
    {
    	if (lazy[root] != -1)
    	{
    		int mid = (l + r) >> 1;
    	lazy[root << 1] = lazy[root]; lazy[root << 1 | 1] = lazy[root]; 
    	tree[root << 1] = (mid - l + 1) * lazy[root], tree[root << 1 | 1] = (r - mid) * lazy[root];
    	lazy[root] = -1;	
    	}
    	
    }
    void build(int l, int r, int root)
    {
    	if (l == r)
    	{
    		tree[root] = 0;
    		lazy[root] = -1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(ls), build(rs);
    	pushup(root);
    }
    void update(int ql, int qr, int add, int l, int r, int root)
    {
    	if (ql <= l && r <= qr)
    	{
    		tree[root] = (r - l + 1) * add;//此处为赋值操作 
    		lazy[root] = add;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	pushdown(l, r, root);
    	if (ql <= mid)
    		update(ql, qr, add, ls);
    	if (qr > mid)
    		update(ql, qr, add, rs);
    	pushup(root);
    }
    int query(int ql, int qr, int l, int r, int root)
    {
    	int res = 0;
    	if (ql <= l && r <= qr)
    		return tree[root];
    	int mid = (l + r) >> 1;
    	pushdown(l, r, root);
    	if (ql <= mid) 
    		res += query(ql, qr, ls);
    	if (qr > mid) 
    		res += query(ql, qr, rs);
    	return res;
    }
    int Q(int a, int b)//a, b的路径 
    {
    	int res = 0;
    	while (top[a] != top[b])
    	{
    		if (dep[top[a]] < dep[top[b]])
    			swap(a, b);
    		res += query(dfn[top[a]], dfn[a], 1, n, 1);
    		a = fat[top[a]];//处理了一个链。 
    	}
    	if (dep[a] > dep[b]) swap(a, b);
    	res += query(dfn[a], dfn[b], 1, n, 1);
    	return res;
    }	
    void U(int a, int b)
    {
    	while (top[a] != top[b])
    	{
    		if (dep[top[a]] < dep[top[b]])
    			swap(a, b);
    		update(dfn[top[a]], dfn[a], 1, 1, n, 1);
    		a = fat[top[a]];//处理了一个链。 
    	}
    	if (dep[a] > dep[b]) swap(a, b);
    	update(dfn[a], dfn[b], 1, 1, n, 1);
    } 
    int main()
    {
    //in:先输出0到他的路径边权和,安装是将其路径上的所有边权变为1,
    //un:求出子树得值,将他的子树全都赋为一个数,求出子树的值,将他的子树全都赋为一个数 
     	scanf("%d", &n);
     	for (int i = 2, a; i <= n; i++)
     		scanf("%d", &a), add(a + 1, i), add(i, a + 1);//先使所有点的编号加1
     	dfs1(1, 0);
     	dfs2(1, 1);
     	scanf("%d", &m);
     	while (m--)
     	{
     		string s; int a;
     		cin >> s; scanf("%d", &a);
     		a++; 
     		if (s[0] == 'i')//安装 
     		{	
    			int a1 = Q(1, a);//查询1到他的路径和。
    			U(1, a);//更改1,a的路径和统统赋为1。
    			int a2 = Q(1, a);
    			printf("%d
    ", a2 - a1);
     		}
     		else
     		{
     			printf("%d
    ", query(dfn[a], dfn[a] + siz[a] - 1, 1, n, 1));//查询子树的和 
     			update(dfn[a], dfn[a] + siz[a] - 1, 0, 1, n, 1); 
    		} 
     	}
     	return 0;
    }
    
  • 相关阅读:
    Promise原理实现(一):前置知识点
    移动端禁用缩放
    多条命令同时执行的包concurrently
    通过面试题学JavaScript知识(1)
    移动设备适配
    css 文本溢出显示省略号
    变量对象的理解
    7.10 日志
    7.9 日志
    JMETER接口测试之自动化环境的配置
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11805886.html
Copyright © 2020-2023  润新知