【codevs1228】蘋果樹【線段樹+dfs序】
題目描述 Description
在卡卡的房子外面,有一棵蘋果樹。每年的春天,樹上總會結出很多的蘋果。卡卡非常喜歡吃蘋果,所以他一直都精心的呵護這棵蘋果樹。我們知道樹是有很多分叉點的,蘋果會長在枝條的分叉點上面,且不會有兩個蘋果結在一起。卡卡很想知道一個分叉點所代表的子樹上所結的蘋果的數目,以便研究蘋果樹哪些枝條的結果能力比較強。
卡卡所知道的是,每隔一些時間,某些分叉點上會結出一些蘋果,但是卡卡所不知道的是,總會有一些調皮的小孩來樹上摘走一些蘋果。
於是我們定義兩種操作:
C x
表示編號為x的分叉點的狀態被改變(原來有蘋果的話,就被摘掉,原來沒有的話,就結出一個蘋果)
G x
查詢編號為x的分叉點所代表的子樹中有多少個蘋果
我們假定一開始的時候,樹上全都是蘋果,也包括作為根結點的分叉1。
輸入描述 Input Description
第一行一個數N (n<=100000)
接下來n-1行,每行2個數u,v,表示分叉點u和分叉點v是直接相連的。
再接下來一行一個數M,(M<=100000)表示詢問數
接下來M行,表示詢問,詢問的格式如題目所述Q x或者C x
輸出描述 Output Description
對於每個Q x的詢問,請輸出相應的結果,每行輸出一個
樣例輸入 Sample Input
3
1 2
1 3
3
Q 1
C 2
Q 1
樣例輸出 Sample Output
3
2
題解:我們知道,在一棵子樹中dfs序是連續的。所以先求出這棵樹的dfs序,記錄一下每個節點在dfs序中的位置。再記錄一下每棵子樹中dfs序的最大值。然後根據dfs序建一棵線段樹。剩下就和裸線段樹一樣了。。
注意資料中有換行,非常坑人。。。
#include<iostream>
#include<cstdio>
using namespace std;
int t[1000001],mx[100001],pos[1000001],point[1000001],next[1000001],cnt,sz;
struct use{
int st,en;
}b[1000001];
int n,u,v,m,aa,bb;
char ch;
void add(int x,int y)
{
next[++cnt]=point[x];point[x]=cnt;
b[cnt].st=x;b[cnt].en=y;
}
void dfs(int x,int fa)
{
pos [x]=++sz;mx[x]=sz;
for (int i=point[x];i;i=next[i])
{
if (b[i].en==fa) continue;
dfs(b[i].en,x);
mx[x]=max(mx[x],mx[b[i].en]);
}
}
void build(int k,int l,int r)
{
int mid;
if (l==r){t[k]=1;return;};
mid=(l+r)/2;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
t[k]=t[2 *k]+t[2*k+1];
}
void change(int k,int l,int r,int x)
{
int mid;
if (l==r&&l==x)
{
if (t[k]==1) t[k]=0;else t[k]=1;
return;
}
mid=(l+r)/2;
if (x<=mid) change(2*k,l,mid,x);
if (x>mid) change(2*k+1,mid+1,r,x);
t[k]=t[2*k]+t[2*k+1];
}
int qsum(int k,int l,int r,int ll,int rr)
{
int mid,ans(0);
if (ll<=l&&r<=rr) return t[k];
mid=(l+r)/2;
if (ll<=mid) ans+=qsum(2*k,l,mid,ll,rr);
if (mid<rr) ans+=qsum(2*k+1,mid+1,r,ll,rr);
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++){scanf("%d%d",&u,&v);add(u,v);add(v,u);}
dfs(1,0);build(1,1,n);cin>>m;
for (int i=1;i<=m;i++)
{
scanf("%*c%*c%c%d",&ch,&aa);
if (ch=='C')
{
change(1,1,n,pos[aa]);
}
if (ch=='Q')
{
printf("%d\n",qsum(1,1,n,pos[aa],mx[aa]));
}
}
}