codeforces 384e

题目大意:

给定n个点,m个询问的无向树(1为根)

下面n个数表示每个点的权值

下面n-1行给出树

操作1:x点权值+v, x的第 i & 1 的儿子-v, 第 !(i&1) 的儿子+v

操作2:询问x点权值

思路:把树上的点用dfs序转换一下就可以用树状数组做了,不过因为更新时有两种更新同时进行所以需要用两个树状数组分别更新就行,很巧妙的树状数组运用

#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn= 200000+10;
const int mod=1e9+7;
const double en=2.718281828459;
using namespace std;
#define inf (ll)1<<60
struct st{
int val,l,r,h;
}q[maxn];
vector<int>g[maxn];
int n,m,cnt,fg[maxn],tree[3][maxn];
void dfs(int u,int h){
    cnt++;
    q[u].l=cnt;
    q[u].h=h;
    fg[u]=1;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(fg[v]==0)
            dfs(v,(h+1)%2);
    }
    q[u].r=cnt;
}
void add(int k,int num,int h){//对k位置的数加上num
    while(k<=n){
        tree[h][k]+=num;
        k+=k&(-k);
    }
}
int read(int k,int h){//查询一到k位置a[i]的和
    int sum=0;
    while(k){
        sum+=tree[h][k];
        k-=k&(-k);
    }
    return sum;
}
int main() {
// freopen("in.txt","r",stdin);
    cin>>n>>m;
    int i;
    for(i=1;i<=n;i++)
        scanf("%d",&q[i].val);
    int a,b,c;
    for(i=1;i<=n-1;i++){
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1,0);
    for(i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        if(a==1){
            scanf("%d",&c);
            add(q[b].l,c,q[b].h);
            add(q[b].r+1,-c,q[b].h);
            add(q[b].l,-c,(q[b].h+1)%2);
            add(q[b].r+1,c,(q[b].h+1)%2);
        }
        else printf("%d\n",q[b].val+read(q[b].l,q[b].h));

    }

    return 0;
}

 

posted @ 2016-08-08 19:45  十目  阅读(224)  评论(0编辑  收藏  举报