hdu 4836 The Query on the Tree(線段樹or樹狀陣列)

weixin_34377065發表於2015-12-20

The Query on the Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 57    Accepted Submission(s): 20


Problem Description
  度度熊近期沉迷在和樹有關的遊戲了。他一直覺得樹是最奇妙的資料結構。

一天他遇到這樣一個問題:
  有一棵樹,樹的每一個點有點權,每次有三種操作:
  1. Query x 表示查詢以x為根的子樹的權值和。


  2. Change x y 表示把x點的權值改為y(0<=y<=100)。


  3. Root x 表示把x變為根。


  如今度度熊想請更聰明的你幫助解決問題。

 

Input
  第一行為資料組數T(1 <= T <= 100)
  每組資料第一行為N(1<= N <= 10000),表示樹的節點數。
  後面N-1行每行有兩個數x,y 。表示x,y之間有一條邊 1<=x,y<=N。初始時樹是以1號節點為根節點。


  之後的一行為N個數表示這N個點的點權(點權的範圍是0到100)。


  然後為整數Q(Q<=1000)為操作次數。


  之後的Q行為描寫敘述中的三種操作。

 

Output
  對於第k組輸入資料。第一行輸出Case #k 接下來對於每一個”Query x”操作。輸出以x為根的子數和。
 

Sample Input
2 5 1 2 1 3 3 4 3 5 1 2 3 4 5 5 Query 1 Change 3 10 Query 1 Root 4 Query 3 8 1 2 1 3 3 4 4 5 5 6 5 7 4 8 1 2 3 4 5 6 7 8 5 Query 1 Query 3 Root 5 Query 3 Query 1
 

Sample Output
Case #1: 15 22 18 Case #2: 36 33 6 3

題意:天朝文字不解釋

題解:我先將樹的點以1為根轉換成一個陣列並記錄每一個點子樹的範圍。就是類似lca的那個樹轉陣列一樣,將一個點分成2個點,dfs的時候到達結點時候生成一個點值為結點本身的值,離開結點生成一個點值為0,然後儲存其這2個點的位置,那麼求某個點的子樹和就變成了求該個區間和了,區間和操作和改變某個點的值都能夠用線段樹or樹狀陣列維護。當須要更改根的時候僅記錄root。我們的樹始終以1為根,不作其他改變。那麼查詢操作。若root不是x的子樹的結點,x的子樹和就是x相應的區間和;若root是x的子樹的結點。就要找出root是x哪個兒子的子樹,然後x的子樹和就是全部數的值減去那個包括root結點的子樹的和。


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
struct node{
    int y,next;
}e[80008];
int head[80008],val[80008],tree[80008];
int sta[80008],ssta[80008],fin[80008];
int a[80008],n,all;
vector<int>v[80008];
void add(int x,int y)
{
    e[all].next=head[x];
    e[all].y=y;
    head[x]=all++;
}
void dfs(int x,int &cou,int fa)
{
    a[cou]=val[x];
    sta[x]=cou++;
    for(int i=head[x];i!=-1;i=e[i].next)
    {
        if(fa==e[i].y) continue;
        dfs(e[i].y,cou,x);
        v[x].push_back(sta[e[i].y]);
    }
    fin[x]=cou++;
}
void build(int l,int r,int pos)
{
    int mid=(l+r)>>1;
    if(l==r){ tree[pos]=a[l]; return; }
    build(l,mid,pos<<1);
    build(mid+1,r,pos<<1|1);
    tree[pos]=tree[pos<<1]+tree[pos<<1|1];
}
void updata(int l,int r,int pos,int x,int y)
{
    int mid=(l+r)>>1;
    if(l==r){ tree[pos]=y; return; }
    if(x<=mid) updata(l,mid,pos<<1,x,y);
    else updata(mid+1,r,pos<<1|1,x,y);
    tree[pos]=tree[pos<<1]+tree[pos<<1|1];
}
int query(int l,int r,int pos,int templ,int tempr)
{
    int mid=(l+r)>>1;
    if(templ<=l&&r<=tempr) return tree[pos];
    if(tempr<=mid) return query(l,mid,pos<<1,templ,tempr);
    else if(templ>mid) return query(mid+1,r,pos<<1|1,templ,tempr);
    return query(l,mid,pos<<1,templ,mid)+query(mid+1,r,pos<<1|1,mid+1,tempr);
}
int main()
{
    int t,x,y,m,cas=1;
    char s[18];

    scanf("%d",&t);
    while(t--)
    {
        memset(head,-1,sizeof(head));
        memset(a,0,sizeof(a));
        all=0;
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        int cou=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",val+i);
            v[i].clear();
        }
        dfs(1,cou,-1);
        for(int i=1;i<=n;i++)
        {
            ssta[sta[i]]=i;
            if(v[i].size()<=0) continue;
            sort(v[i].begin(),v[i].end());
        }
        build(1,cou-1,1);
        scanf("%d",&m);
        int root=1;
        printf("Case #%d:\n",cas++);
        while(m--)
        {
            scanf("%s",s);
            if(s[0]=='C')
            {
                scanf("%d%d",&x,&y);
                updata(1,cou-1,1,sta[x],y);
            }
            else if(s[0]=='R') scanf("%d",&root);
            else
            {
                scanf("%d",&x);
                if(x==root) printf("%d\n",tree[1]);
                else if(sta[x]<sta[root]&&fin[root]<fin[x])
                {
                    int temp=upper_bound(v[x].begin(),v[x].end(),sta[root]) - v[x].begin();
                    temp=ssta[v[x][temp-1]];
                    printf("%d\n",tree[1]-query(1,cou-1,1,sta[temp],fin[temp]));
                }
                else printf("%d\n",query(1,cou-1,1,sta[x],fin[x]));
            }
        }
    }

    return 0;
}


相關文章