1. 程式人生 > >Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+樹狀數組

Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+樹狀數組

val child mem 節點 using ani nts 小朋友 better

Propagating tree

Time Limit: 20 Sec

Memory Limit: 256 MB

題目連接

http://codeforces.com/contest/383/problem/C

Description

Iahub likes trees very much. Recently he discovered an interesting tree named propagating tree. The tree consists of n nodes numbered from 1 to n, each node i having an initial value ai. The root of the tree is node 1.

This tree has a special property: when a value val is added to a value of node i, the value -val is added to values of all the children of node i. Note that when you add value -val to a child of node i, you also add -(-val) to all children of the child of node i and so on. Look an example explanation to understand better how it works.

This tree supports two types of queries:

? "1 x val" — val is added to the value of node x;
? "2 x" — print the current value of node x.

In order to help Iahub understand the tree better, you must answer m queries of the preceding type.

Input

The first line contains two integers n and m (1?≤?n,?m?≤?200000). The second line contains n integers a1, a2, ..., an (1?≤?ai?≤?1000). Each of the next n–1 lines contains two integers vi and ui (1?≤?vi,?ui?≤?n), meaning that there is an edge between nodes vi and ui.

Each of the next m lines contains a query in the format described above. It is guaranteed that the following constraints hold for all queries: 1?≤?x?≤?n,?1?≤?val?≤?1000.

Output

For each query of type two (print the value of node x) you must print the answer to the query on a separate line. The queries must be answered in the order given in the input.

Sample Input

5 5
1 2 1 1 2
1 2
1 3
2 4
2 5
1 2 3
1 1 2
2 1
2 2
2 4

Sample Output

3
3
0

HINT

題意

給出一顆有n個節點並一1為根節點的樹,每個節點有它的權值,現在進行m次操作,操作分為添加和查詢,當一個節點的權值添加val,則它的孩子節點的權值要添加-b。

題解:

dfs序+樹狀數組

學過或者沒學過樹鏈剖分的小朋友應該知道dfs序可以使得任意節點的子樹變成一段連續的區間,這樣就可以進行區間修改了。

但是這道題對子樹層數的不同,操作也不一樣,確實很麻煩呀。

我也是一臉懵逼,看完題解才發現原來如此神奇!!

其實我們可以把樹分層,分成奇數層和偶數層(根據到根節點的距離),然後建兩個樹狀數組,如果是對奇數層的點進行操作那麽就給第一個樹狀數組相應的區間加上val,如果是偶數層就更新第二個樹狀數組。

這樣對於某個節點i(假設是奇數層),那麽此刻權值就是樹狀數組1-樹狀數組2。

感覺這種分層的思想很是神奇。

代碼

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 400050
int n,m,cnt,w[N],a[N],c[2][N];
int dp[N],rk[N],kth[N],size[N];
int tot,last[N];
struct Edge{int from,to,s;}edges[N<<1];
template<typename T>void read(T&x)
{
    ll k=0; char c=getchar();
    x=0;
    while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
    if (c==EOF)exit(0);
    while(isdigit(c))x=x*10+c-'0',c=getchar();
    x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
void AddEdge(int x,int y)
{
    edges[++tot]=Edge{x,y,last[x]};
    last[x]=tot;
}
void dfs(int x,int pre)
{
    dp[x]=1-dp[pre];
    rk[x]=++cnt;
    kth[cnt]=x;
    size[x]=1;
    for(int i=last[x];i;i=edges[i].s)
    {
        Edge &e=edges[i];
        if (e.to==pre)continue;
        dfs(e.to,x);
        size[x]+=size[e.to];
    }
}
void update(int *c,int x,int tt)
{while(x<=n){c[x]+=tt;x+=x&-x;}}
int get_sum(int *c,int x)
{int ans=0;while(x){ans+=c[x];x-=x&-x;}return ans;}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("aa.in","r",stdin);
#endif
    read(n);read(m);
    for(int i=1;i<=n;i++)read(w[i]);
    for(int i=1;i<=n-1;i++)
    {
        int x,y;
        read(x); read(y);
        AddEdge(x,y);
        AddEdge(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        int id,x,val;
        read(id);
        if (id==1)
        {
            read(x); read(val);
            update(c[dp[x]],rk[x],val);
            update(c[dp[x]],rk[x]+size[x],-val);
        }
        if (id==2)
        {
            read(x);
            int ans=get_sum(c[dp[x]],rk[x])-get_sum(c[1-dp[x]],rk[x]);
            ans+=w[x];
            printf("%d\n",ans);
        }
    }
        
}

Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+樹狀數組