ZJOI 2008 樹的統計
阿新 • • 發佈:2017-08-25
dispose med ret || names inline push_back logs isp
ZJOI2008 樹的統計
題目描述
一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。
我們將以下面的形式來要求你對這棵樹完成一些操作:
I. CHANGE u t : 把結點u的權值改為t
II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值
III. QSUM u v: 詢問從點u到點v的路徑上的節點的權值和
註意:從點u到點v的路徑上的節點包括u和v本身
輸入輸出格式
輸入格式:
輸入文件的第一行為一個整數n,表示節點的個數。
接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。
接下來一行n個整數,第i個整數wi表示節點i的權值。
接下來1行,為一個整數q,表示操作的總數。
接下來q行,每行一個操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式給出。
輸出格式:
對於每個“QMAX”或者“QSUM”的操作,每行輸出一個整數表示要求輸出的結果。
輸入輸出樣例
輸入樣例#1:4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4輸出樣例#1:
4 1 2 2 10 6 5 6 5 16
說明
對於100%的數據,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。
這是一題明擺著的樹剖題,
我們只需要用線段樹維護兩個信息,
最大值和總和,
樹剖就是,
路經查詢,單點修改
#include <algorithm> #include <iostream> #include <cstdio> #include <vector> #include <string> using namespace std; const int maxn = 100000 + 10; int cnt = 0,map[maxn],val[maxn],num[maxn],size[maxn],father[maxn],son[maxn],top[maxn],dep[maxn],w[maxn]; int n,m,r,p; vector<int> edges[maxn]; inline void dfs1(int now,int f) { //第一次dfs size[now] = 1; father[now] = f; dep[now] = dep[father[now]]+1; for (size_t i = 0;i < edges[now].size();i++) if (edges[now][i] != f) { dfs1(edges[now][i],now); size[now] += size[edges[now][i]]; if (size[son[now]] < size[edges[now][i]] || !son[now]) son[now] = edges[now][i]; } } inline void dfs2(int now,int ntop) { //第二次dfs top[now] = ntop; num[now] = ++cnt; map[num[now]] = now; if (son[now]) dfs2(son[now],ntop); for (size_t i = 0;i < edges[now].size();i++) if (edges[now][i] != father[now] && edges[now][i] != son[now]) dfs2(edges[now][i],edges[now][i]); } struct seg { int maxv,sum,mark,l,r; } tree[maxn*4]; inline void pushup(int root) { //線段樹上傳更新 tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum; tree[root].maxv = max(tree[root<<1].maxv,tree[root<<1|1].maxv); } inline void BuildTree(int l,int r,int root) { //建樹 tree[root].l = l; tree[root].r = r; tree[root].mark = 0; if (l == r) { tree[root].sum = val[map[l]]; tree[root].maxv = val[map[l]]; return; } int mid = l+r>>1; BuildTree(l,mid,root<<1); BuildTree(mid+1,r,root<<1|1); pushup(root); } inline void Update(int l,int r,int num,int root,int x) { //單點修改 if (l == r) { tree[root].sum = x; tree[root].maxv = x; return; } int mid = l+r>>1; if (num <= mid) Update(l,mid,num,root<<1,x); else Update(mid+1,r,num,root<<1|1,x); pushup(root); } inline int QuerySum(int l,int r,int ql,int qr,int root) { //區間求和 if (ql > r || qr < l) return 0; if (ql <= l && qr >= r) return tree[root].sum; int mid = l+r>>1; return QuerySum(l,mid,ql,qr,root<<1)+QuerySum(mid+1,r,ql,qr,root<<1|1); } inline int QueryMax(int l,int r,int ql,int qr,int root) { //區間求最大 if (ql > r || qr < l) return -999999999; if (ql <= l && qr >= r) return tree[root].maxv; int mid = l+r>>1; return max(QueryMax(l,mid,ql,qr,root<<1),QueryMax(mid+1,r,ql,qr,root<<1|1)); } inline int QuerySumEdges(int u,int v) { //路徑求和 int topu = top[u]; int topv = top[v]; int sum = 0; while (topu != topv) { if (dep[topu] < dep[topv]) { swap(topu,topv); swap(u,v); } sum += QuerySum(1,cnt,num[topu],num[u],1); u = father[topu]; topu = top[u]; } if (dep[u] > dep[v]) swap(u,v); return sum+QuerySum(1,cnt,num[u],num[v],1); } inline int QueryMaxEdges(int u,int v) { //路徑求最大 int topu = top[u]; int topv = top[v]; int Max = -999999999; while (topu != topv) { if (dep[topu] < dep[topv]) { swap(topu,topv); swap(u,v); } Max = max(Max,QueryMax(1,cnt,num[topu],num[u],1)); u = father[topu]; topu = top[u]; } if (dep[u] > dep[v]) swap(u,v); return max(Max,QueryMax(1,cnt,num[u],num[v],1)); } int main() { ios :: sync_with_stdio(false); cin >> n; for (int i = 1,u,v;i < n;i++) { cin >> u >> v; edges[u].push_back(v); edges[v].push_back(u); } for (int i = 1;i <= n;i++) cin >> val[i]; dfs1(1,0); dfs2(1,1); BuildTree(1,cnt,1); cin >> m; while (m--) { string dispose; int u,v; cin >> dispose >> u >> v; if (dispose == "CHANGE") Update(1,cnt,num[u],1,v); else if (dispose == "QSUM") cout << QuerySumEdges(u,v) << endl; else cout << QueryMaxEdges(u,v) << endl; } return 0; }
ZJOI 2008 樹的統計