• poj3321


    树状数组

    题意:给定一棵树,某些节点上有苹果,多次询问各子树上的节点数,并且在询问的中途随时可能新增和删除苹果。

    分析:dfs遍历树的同时,对每个点标注时间,每个点有一个开始时间和一个结束时间,把这两个时间当做下标,该点的苹果个数(1或0)填入数组的两个对应位。子树中结点的时间段一定是根节点时间段的子段,所以求子树苹果数,只需求数组某区间的和即可。用树状数组比较快。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    #define maxn  200005
    
    struct sedge
    {
    	int v, next;
    }edge[maxn];
    
    struct sfork
    {
    	int s, e;
    }fork[maxn];
    
    int edgenum, head[maxn], xtime, ar[maxn * 2], apple[maxn], N;
    
    void addedge(int a, int b)
    {
    	edge[edgenum].v = b;
    	edge[edgenum].next = head[a];
    	head[a] = edgenum;
    	edgenum++;
    }
    
    void dfs(int a)
    {
    	fork[a].s = xtime;
    	xtime++;
    	for (int i = head[a]; i != -1; i = edge[i].next)
    			dfs(edge[i].v);
    	fork[a].e = xtime;
    	xtime++;
    }
    
    int lowbit(int t)
    {
    	return t &(-t);
    }
    
    void add(int i, int v)
    {
    	for (; i < N; ar[i] += v, i += lowbit(i));
    }
    
    int sum(int i)
    {
    	int s = 0;
    	for (; i > 0; s += ar[i], i-=lowbit(i));
    	return s;
    }
    int main()
    {
    	//freopen("D:\\t.txt", "r", stdin);
    	edgenum = 0;
    	xtime = 1;
    	memset(head, -1, sizeof(head));
    	int n;
    	scanf("%d", &n);
    	for (int i = 0; i < n - 1; i++)
    	{
    		int a, b;
    		scanf("%d%d", &a, &b);
    		addedge(a, b);
    	}
    	dfs(1);
    	memset(ar, 0, sizeof(ar));
    	N = n * 2;
    	for (int i = 1; i <= N; i++)
    		ar[i] = (i) - (i - lowbit(i));
    	for (int i = 1; i <= n; i++)
    		apple[i] = 1;
    	int q;
    	scanf("%d", &q);
    	getchar();
    	for (int i = 0; i < q; i++)
    	{
    		char ch;
    		int num;
    		scanf("%c%d", &ch, &num);
    		getchar();
    		if (ch == 'C')
    		{
    			int temp;
    			if (apple[num] == 1)
    				temp = -1;
    			else
    				temp = 1;
    			add(fork[num].s, temp);
    			add(fork[num].e, temp);
    			apple[num] += temp;
    		}
    		else
    			printf("%d\n", (sum(fork[num].e) - sum(fork[num].s))/2 + apple[num]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    DataSet中的数据全部插入数据库
    SQL养成一个好习惯是一笔财富
    C#不管什么四舍五入,只要是小数取整就得加1
    XMLNode与XmlNodeList
    ASP.NET2.0中配置文件的加密与解密
    编写一个文件目录常用操作的类
    上传文件的方法
    使用javascript 实现.net 验证控件功能
    SQLSERVER如何获取一个数据库中的所有表的名称、一个表中所有字段的名称
    Android之开启内置闹钟与已安装的应用程序设置
  • 原文地址:https://www.cnblogs.com/rainydays/p/1948628.html
Copyright © 2020-2023  润新知