zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11805886.html
Copyright © 2011-2022 走看看