BZOJ1103 大都市 DFS序 樹狀數組維護差分數組

BZOJ1103 大都市

問題描述

在經濟全球化浪潮的影響下,習慣於漫步在清晨的鄉間小路的郵遞員Blue Mary也開始騎着摩托車傳遞郵件了。
不過,她經常回憶起以前在鄉間漫步的情景。昔日,鄉下有依次編號爲1..n的n個小村莊,某些村莊之間有一些雙向的土路。從每個村莊都恰好有一條路徑到達村莊1(即比特堡)。並且,對於每個村莊,它到比特堡的路徑恰好只經過編號比它的編號小的村莊。

另外,對於所有道路而言,它們都不在除村莊以外的其他地點相遇。在這個未開化的地方,從來沒有過高架橋和地下鐵道。隨着時間的推移,越來越多的土路被改造成了公路。至今,Blue Mary還清晰地記得最後一條土路被改造爲公路的情景。現在,這裏已經沒有土路了——所有的路都成爲了公路,而昔日的村莊已經變成了一個大都市。
Blue Mary想起了在改造期間她送信的經歷。她從比特堡出發,需要去某個村莊,並且在兩次送信經歷的間隔期間,有某些土路被改造成了公路.
現在Blue Mary需要你的幫助:計算出每次送信她需要走過的土路數目。(對於公路,她可以騎摩托車;而對於土路,她就只好推車了。)

輸入格式

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

輸出格式

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

樣例輸入

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

樣例輸出

2
1
0
1


樹鏈剖分當然是可以搞的。但是這樣會比較卡。

考慮把一條邊改成公路的影響,設這條邊連接的較深的節點爲x ,那麼x 的子樹到根節點的答案都會減去1。這讓我們想起了DFS序的性質:x 及其子樹表示的區間是[In[x],Out[x]] ,而且一定是連續的一段。那麼這個操作就可以轉換爲對一個連續區間減去了1。另一個操作就是查詢某個節點的值。

實現區間修改的操作,常常採用兩種方式:

1.線段樹
2.差分數組

差分數組本來是修改O(1) ,查詢O(n) 的時間複雜度,暴力求前綴和太慢了。本題查詢次數可能會很多,這樣一定會TLE。因此,採用樹狀數組維護差分數組的方式,雖然修改的時間複雜度增大爲了O(logn) ,但是查詢被大大優化爲O(logn) ,這樣就可以過這道題了。

有了樹狀數組當然就不選線段樹了。


#include<stdio.h>
#define MAXN 250005
#define MAXM 500005

int N,M;

int en[MAXM],nex[MAXM],las[MAXN],tot;
void ADD(int x,int y)
{
    en[++tot]=y;
    nex[tot]=las[x];
    las[x]=tot;
}

int In[MAXN],Out[MAXN],dep[MAXN],VT;
void DFS(int x,int f)
{
    int i,y;
    In[x]=++VT;dep[x]=dep[f]+1;
    for(i=las[x];i;i=nex[i])
    {
        y=en[i];
        if(y!=f)DFS(y,x);
    }
    Out[x]=VT;
}

int C[MAXN];

void Modify(int x,int k){for(int i=x;i<=N;i+=(i&-i))C[i]+=k;}

int GetSum(int x)
{
    int i,sum=0;
    for(i=x;i;i-=(i&-i))sum+=C[i];
    return sum;
}

int mian()
{
    int i,x,y,a,b;
    char op[3];

    scanf("%d",&N);
    for(i=1;i<N;i++)
    {
        scanf("%d%d",&x,&y);
        ADD(x,y);ADD(y,x);
    }

    DFS(1,0);

    for(i=2;i<=N;i++)Modify(In[i],1),Modify(Out[i]+1,-1);

    scanf("%d",&M);
    for(i=1;i<=N+M-1;i++)
    {
        scanf("%s",op);
        if(op[0]=='W')
        {
            scanf("%d",&x);
            printf("%d\n",GetSum(In[x]));
        }
        else
        {
            scanf("%d%d",&x,&y);
            if(In[x]<In[y])a=In[y],b=Out[y];
            else a=In[x],b=Out[x];
            Modify(a,-1);
            Modify(b+1,1);
        }
    }
}
const int main_stack=16;
char my_stack[128<<20];
int main() {
    __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");
    __asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp");
    mian();
    __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章