标签:ack dfs pre 输入输出 i++ 输入 表示 最大 格式
一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。
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
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; }
标签:ack dfs pre 输入输出 i++ 输入 表示 最大 格式
原文地址:http://www.cnblogs.com/lrj124/p/7429678.html