1. 程式人生 > >codevs——1228 蘋果樹

codevs——1228 蘋果樹

struct des st2 () || dfs ext rip 兩個

1228 蘋果樹

時間限制: 1 s 空間限制: 128000 KB 題目等級 : 鉆石 Diamond 題目描述 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

拿到這個題目以後,我們第一眼看到的會是:有m次詢問,每次詢問2種操作。那麽就可以很快的get到這個題是要用線段樹。

但是問題又來了,現在他給我們的是一個樹啊,而且我們線段樹維護的是一個序列,那我們就要先辦法將這棵樹轉化成一個序列

我們想一下要用什麽方法完成這個操作呢?? 對!就是dfs序!

我們現對於我們建出來的樹跑一遍dfs,然後求出每一個節點的dfs序,同時處理出每一個節點的子樹的大小,這樣我們可以保證每一棵子樹內的所有的節點都是相連的。以一個節點為子樹的區間即為從這個節點到這個節點+其子樹的大小+1,當我們詢問一個節點的蘋果個數是既可以轉換成詢問這個區間的大小。在我們進行蘋果的更改時,即為對一個點進行單點修改,我們進行單點修改的時候我們直接對其進行取反既可以。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 110000
using namespace std;
char ch;
int n,m,q,x,y,s,tot,ans;
int head[N],size[N],list1[N],list2[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0; ch=getchar();}
    return x*f;
}
struct Edge
{
    int next,to,from;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
struct Tree
{
    int l,r,w;
}tree[N*4];
int dfs(int x)
{
    size[x]=1,list1[x]=++s,list2[s]=x;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        dfs(t);
        size[x]+=size[t];
    }
}
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=1;
        return ;
    }
    int mid=(tree[k].l+tree[k].r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void change_point(int k)
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=!tree[k].w;
        return ;
    }
    int mid=(tree[k].r+tree[k].l)/2;
    if(x<=mid) change_point(k<<1);
    else change_point(k<<1|1);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void ask_interval(int k)
{
    if(tree[k].l>=x&&tree[k].r<=y)
    {
        ans+=tree[k].w;
        return ;
    }
    int mid=(tree[k].l+tree[k].r)>>1;
    if(x<=mid) ask_interval(k<<1);
    if(y>mid)  ask_interval(k<<1|1);
}
int main()
{
    n=read();
    for(int i=1;i<n;i++)
     x=read(),y=read(),add(x,y);
    dfs(1);
    build(1,1,n);
    m=read();
    while(m--)
    {
        cin>>ch;
        q=read();
        x=list1[q];ans=0;
        if(ch==C) change_point(1);
        else 
        {
            y=x+size[q]-1;ask_interval(1);
            printf("%d\n",ans);
        }
    }
    return 0;
}

codevs——1228 蘋果樹