1. 程式人生 > 實用技巧 >【樹上差分+樹狀陣列】bzoj 1103 大都市meg

【樹上差分+樹狀陣列】bzoj 1103 大都市meg

Description

在經濟全球化浪潮的影響下,習慣於漫步在清晨的鄉間小路的郵遞員Blue Mary也開始騎著摩托車傳遞郵件了。不過,她經常回憶起以前在鄉間漫步的情景。昔日,鄉下有依次編號為1..n的n個小村莊,某些村莊之間有一些雙向的土路。從每個村莊都恰好有一條路徑到達村莊1(即位元堡)。並且,對於每個村莊,它到位元堡的路徑恰好只經過編號比它的編號小的村莊。另外,對於所有道路而言,它們都不在除村莊以外的其他地點相遇。在這個未開化的地方,從來沒有過高架橋和地下鐵道。隨著時間的推移,越來越多的土路被改造成了公路。至今,Blue Mary還清晰地記得最後一條土路被改造為公路的情景。現在,這裡已經沒有土路了——所有的路都成為了公路,而昔日的村莊已經變成了一個大都市。 Blue Mary想起了在改造期間她送信的經歷。她從位元堡出發,需要去某個村莊,並且在兩次送信經歷的間隔期間,有某些土路被改造成了公路.現在Blue Mary需要你的幫助:計算出每次送信她需要走過的土路數目。(對於公路,她可以騎摩托車;而對於土路,她就只好推車了。)

Input

第一行是一個數n(1 < = n < = 2 50000).
以下n-1行,每行兩個整數a,b(1 < = a以下一行包含一個整數m(1 < = m < = 2 50000),表示Blue Mary曾經在改造期間送過m次信。
以下n+m-1行,每行有兩種格式的若干資訊,表示按時間先後發生過的n+m-1次事件:
若這行為 A a b(a若這行為 W a, 則表示Blue Mary曾經從位元堡送信到村莊a。

Output

有m行,每行包含一個整數,表示對應的某次送信時經過的土路數目。

Sample Input

5
1 2
1 3
1 4
4 5
4
W 5
A 1 4
W 5
A 4 5
W 5
W 2
A 1 2
A 1 3

Sample Output

2
1
0
1

首先dfs一遍,找到每個點的入隊和出隊的時間,然後在這個序列上標記-1和1,然後利用樹狀陣列進行計算即可

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=250005;
int cnt,n,m,head[maxn],out[maxn],in[maxn],times;
struct edge
{
    int to,nxt;
}e[maxn<<1];
char s[10];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxt
=head[x]; head[x]=cnt; } void dfs(int u,int fa) { in[u]=++times; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dfs(to,u); } out[u]=++times; } int c[maxn<<1]; int lowbit(int x) { return x&(-x); } void update(int x,int v) { for(int i=x;i<=n*2;i+=lowbit(i)) c[i]+=v; } int query(int x) { int res=0; for(int i=x;i;i-=lowbit(i)) res+=c[i]; return res; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n); int x,y; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); for(int i=1;i<=n;i++) update(in[i],1),update(out[i],-1); scanf("%d",&m); for(int i=1;i<=m+n-1;i++) { scanf("%s",s); if(s[0]=='A') { scanf("%d%d",&x,&y); update(in[y],-1); update(out[y],1); } else { scanf("%d",&x); printf("%d\n",query(in[x])-1); } } return 0; }