LibreOJ #144. DFS 序 1
阿新 • • 發佈:2018-12-22
題面:
給一棵有根樹,這棵樹由編號為1…N的N個結點組成。根結點的編號為R。每個結點都有一個權值,結點i的權值為vi。接下來有M組操作,操作分為兩類:
1 a x
,表示將結點a的權值增加x;2 a
,表示求結點a的子樹上所有結點的權值之和。
輸入格式:
- 第一行有三個整數 N,M和R。
- 第二行有 N 個整數,第 i 個整數表示 vi。
- 在接下來的 N−1 行中,每行兩個整數,表示一條邊。
- 在接下來的 M 行中,每行一組操作。
輸出格式:
對於每組 2 a
操作,輸出一個整數,表示「以結點 a 為根的子樹」上所有結點的權值之和。
資料範圍與提示:
解析:在求出此樹的dfs序之後,子樹是一段連續的區間,可以將對子樹的區間操作直接化為對應序列的區間操作。
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll MAXN=1e6+5; int n,m,root,a[MAXN]; struct Edge{ int to,next; }edge[MAXN*2]; int head[MAXN],tot; void addEdge(int u,int v) { tot++; edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot; } ll bit[MAXN]; inline int lowbit(int x){return x&(-x);} void add(int i,int v) { while(i<=n) { bit[i]+=v; i+=lowbit(i); } } ll sum(int i) { ll res=0; while(i>0) { res+=bit[i]; i-=lowbit(i); } return res; } int Index,l[MAXN],r[MAXN]; //l[u]和r[u]分別是以u為根節點的子樹對應的區間左右端點 void dfs(int u,int fa) { l[u]=++Index; add(Index,a[u]); for(int i=head[u];i;i=edge[i].next) { int to=edge[i].to; if(to==fa) continue; dfs(to,u); } r[u]=Index; } int inline 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; } int main() { int u,v,op,pos,val; n=read();m=read();root=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<n;i++) { u=read();v=read(); addEdge(u,v);addEdge(v,u); } dfs(root,0); for(int i=1;i<=m;i++) { op=read(); if(op==1){ pos=read();val=read(); add(l[pos],val); }else{ pos=read(); printf("%lld\n",sum(r[pos])-sum(l[pos]-1)); } } return 0; }