题意:每个分叉点及末梢可能有苹果(最多1个), 每次可以摘掉一个苹果,或有一个苹果新长出来,随时查询某个分叉点所在的子树里, 一共有多少个苹果。
思路:深度优先遍历整个苹果树,为每个节点标记一个开始时间和结束时间(所有时间都不相同),显然子树里面所有节点的开始和结束时间,都位于子树树根的开始和结束时间之间。那么苹果的有无只需在开始时间那个点(在结束时间那个点上也可以)上面进行加减1的操作即可。然后每次查询就看看从开始点到结束点之间的和一共是多少。用线段树或者树状数组皆可。树状数组容易写,遂用之。
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define N 100005 #define INF 0x3fffffff using namespace std; #define N 100005 int tree[N<<1]; struct edge{ int y,next; }e[N<<1]; int first[N],top,n,q,len; int s[N],w[N],flag[N]; void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } void dfs(int x){//对树进行dfs,得到起始和终止的时间戳 int i; s[x] = ++len; for(i = first[x];i!=-1;i=e[i].next) if(!s[e[i].y]) dfs(e[i].y); w[x] = ++len; } int lowbit(int x){ return x&(-x); } void addtree(int i,int x){ for(int j = i;j<=2*n;j+=lowbit(j)) tree[j] += x; } int sum(int x){ int i,res = 0; for(i = x;i>=1;i-=lowbit(i)) res += tree[i]; return res; } int main(){ int i,a,b,x; char ch; scanf("%d",&n); memset(s,0,sizeof(s)); memset(first,-1,sizeof(first)); top = len = 0; for(i = 1;i<n;i++){ scanf("%d %d",&a,&b); add(a,b); add(b,a); } dfs(1); for(i = 1;i<=n;i++){ flag[i] = 1; addtree(s[i],1);//初始所有fork上都有苹果 } scanf("%d",&q); while(q--){ getchar(); ch = getchar(); scanf("%d",&x); if(ch == 'Q') printf("%d\n",sum(w[x])-sum(s[x]-1)); else{ if(flag[x])//有变成没有,那么在相应时间戳上去掉这个苹果即可 addtree(s[x], -1); else addtree(s[x], 1); flag[x] = 1-flag[x]; } } return 0; }
poj3263:计数的思路如出一辙。需要注意的是a看到b和b看到a是一个意思,不能重复计数,所以要筛一遍。另外题目给的最高高度的索引是没有用的。
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <cstdlib> using namespace std; #define clc(s,t) memset(s,t,sizeof(s)) #define INF 0x3fffffff #define N 10005 struct node{ int a,b; }s[N]; int tree[N]; int n,m,h,t; int cmp(node x,node y){ if(x.a == y.a) return x.b<y.b; return x.a<y.a; } int lowbit(int x){ return x&(-x); } void add(int i,int x){ for(int j = i;j<=n;j+=lowbit(j)) tree[j] += x; } int sum(int i){ int j,res=0; for(j = i;j>=1;j-=lowbit(j)) res += tree[j]; return res; } int main(){ int i,j,x,y; scanf("%d %d %d %d",&n,&t,&h,&m); for(i = 0;i<m;i++){ scanf("%d %d",&s[i].a,&s[i].b); if(s[i].a > s[i].b) swap(s[i].a,s[i].b); } sort(s,s+m,cmp); for(i = 0;i<m;i++){ if(i && s[i].a==s[i-1].a && s[i].b==s[i-1].b)//去掉重复的 continue; add(s[i].a+1,-1); add(s[i].b,1); } for(i = 1;i<=n;i++) printf("%d\n",h+sum(i)); return 0; }