Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 7444 | Accepted: 1925 |
Description
Input
Output
Sample Input
3 3 1 1 2 1 2 3 2 0 2 1 2 3 0 3
Sample Output
13
WA8次才过,就因为用错了数组。。。
题意:有N个点和N-1条无向边构成了一棵树。给你起点S和Q次查询,查询分两种:
一,0 a 让你求所在节点到a的最短距离;二,1 a b 把第 a 条边的边权改为b。
思路:用dist[i]存储节点i到root的最短距离,用node[i]记录i节点在DFS树中的深度。
1,求两节点间最短距离——LCA转RMQ算法解决,对于a、b两点距离,有dist[a] + dist[b] - 2 * dist[LCA(a, b)];
2,修改边权的环节——邻接表建边,找到要修改的边很简单。但一条边边权的修改最坏情况下会影响到N-1个点的dist[]值,这样对下面查询两点最短距离造成很大影响,我们要做的是——更新那些受影响的点的dist值。设要修改的边起点为a,终点为b。那我们必须要知道这条边边权的改变影响到哪些点的dist值,显然,树中被影响的节点是——深度大于max(node[a], node[b])的点(并不是所有),知道这点实现更新dist[]就简单了。
过程:
记录修改边起点a和终点b并求出边权变化量change(变化后的 - 变化前的)。然后从max(node[a], node[b])j即深度较大的点向下搜索,在搜索过程中修改dist值 即 dist[] += change。
注意:在我的代码work(u, fa, change)中,u 是起点和终点里深度较大的点,fa则看作是u的父节点(深度比u小),不要弄混淆了。还有起点S要随时更新。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <algorithm> #define MAXN 100000+100 #define MAXM 400000+100 using namespace std; struct Edge { int from, to, val, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int vs[MAXN<<1]; int depth[MAXN<<1]; int node[MAXN];//记录节点的深度 int id[MAXN]; int dfs_clock;//时间戳 int dist[MAXN]; int N, Q, S;//N个点 Q次查询 S起点 void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w) { Edge E = {u, v, w, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } void getMap() { int a, b, c; for(int i = 1; i < N; i++) { scanf("%d%d%d", &a, &b, &c); addEdge(a, b, c), addEdge(b, a, c); } } void DFS(int u, int fa, int d)//遍历整棵树 { node[u] = d;//u节点的深度优先数 id[u] = dfs_clock; vs[dfs_clock] = u; depth[dfs_clock++] = d; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; dist[v] = dist[u] + edge[i].val; DFS(v, u, d+1); vs[dfs_clock] = u; depth[dfs_clock++] = d; } } void find_depth() { dfs_clock = 1; memset(vs, 0, sizeof(vs)); memset(depth, 0, sizeof(depth)); memset(node, 0, sizeof(node)); memset(id, 0, sizeof(id)); memset(dist, 0, sizeof(dist)); DFS(1, -1, 0); } int dp[MAXN<<1][30]; void RMQ_init(int NN)//RMQ预处理区间 最小值 { for(int i = 1; i <= NN; i++) dp[i][0] = i; for(int j = 1; (1<<j) <= NN; j++) { for(int i = 1; i + (1<<j) - 1 <= NN; i++) { int a = dp[i][j-1]; int b = dp[i + (1<<(j-1))][j-1]; if(depth[a] <= depth[b]) dp[i][j] = a; else dp[i][j] = b; } } } int query(int L, int R) { int k = 0; while((1<<(k+1)) <= R-L+1) k++; int a = dp[L][k]; int b = dp[R - (1<<k) + 1][k]; if(depth[a] <= depth[b]) return a; else return b; } int LCA(int u, int v) { int x = id[u]; int y = id[v]; if(x >= y) return vs[query(y, x)]; else return vs[query(x, y)]; } void work(int u, int fa, int change) { dist[u] += change; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; work(v, u, change); } } void solve() { int op, a, b; while(Q--) { scanf("%d", &op); if(op == 0) { scanf("%d", &a); printf("%d\n", dist[S] + dist[a] - 2 * (dist[LCA(S, a)])); S = a;//变换起点 } else { scanf("%d%d", &a, &b);//把第a条边上的权值改为b int k = (a-1)<<1;//边的编号 int change = b - edge[k].val;//改变量 edge[k].val = edge[k^1].val = b;//改变 int a = edge[k].from; int b = edge[k].to;//记录变动边的起点终点 //因为该边权值被改变,深度大于它们的点的dist也要改变 int u = node[a] < node[b] ? a : b; int v = node[a] > node[b] ? a : b; work(v, u, change);//改变 所有被影响的dist值 } } } int main() { while(scanf("%d%d%d", &N, &Q, &S) != EOF) { init(); getMap(); find_depth(); RMQ_init(dfs_clock - 1); solve(); } return 0; }
树链剖分:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <string> #define INF 0x3f3f3f3f #define eps 1e-8 #define MAXN (100000+10) #define MAXM (300000+10) #define Ri(a) scanf("%d", &a) #define Rl(a) scanf("%lld", &a) #define Rf(a) scanf("%lf", &a) #define Rs(a) scanf("%s", a) #define Pi(a) printf("%d\n", (a)) #define Pf(a) printf("%.2lf\n", (a)) #define Pl(a) printf("%lld\n", (a)) #define Ps(a) printf("%s\n", (a)) #define W(a) while((a)--) #define CLR(a, b) memset(a, (b), sizeof(a)) #define MOD 1000000007 #define LL long long #define lson o<<1, l, mid #define rson o<<1|1, mid+1, r #define ll o<<1 #define rr o<<1|1 #define PI acos(-1.0) #pragma comment(linker, "/STACK:102400000,102400000") #define fi first #define se second using namespace std; struct Tree{ int l, r, sum; }; Tree tree[MAXN<<2]; void PushUp(int o){ tree[o].sum = tree[ll].sum + tree[rr].sum; } void Build(int o, int l, int r) { tree[o].l = l; tree[o].r = r; tree[o].sum = 0; if(l == r) return ; int mid = (l + r) >> 1; Build(lson); Build(rson); } void Update(int o, int pos, int v) { if(tree[o].l == tree[o].r) { tree[o].sum = v; return ; } int mid = (tree[o].l + tree[o].r) >> 1; if(pos <= mid) Update(ll, pos, v); else Update(rr, pos, v); PushUp(o); } int Query(int o, int L, int R) { if(tree[o].l == L && tree[o].r == R) return tree[o].sum; int mid = (tree[o].l + tree[o].r) >> 1; if(R <= mid) return Query(ll, L, R); else if(L > mid) return Query(rr, L, R); else return Query(ll, L, mid) + Query(rr, mid+1, R); } struct Edge{ int from, to, val, next; }; Edge edge[MAXN<<1]; int head[MAXN], edgenum; void init(){ edgenum = 0; CLR(head, -1); } void addEdge(int u, int v, int w) { Edge E = {u, v, w, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } int son[MAXN], num[MAXN]; int top[MAXN], pos[MAXN], id; int dep[MAXN], pre[MAXN]; void DFS1(int u, int fa, int d) { dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue; DFS1(v, u, d+1); num[u] += num[v]; if(son[u] == -1 || num[son[u]] < num[v]) son[u] = v; } } void DFS2(int u, int T) { top[u] = T; pos[u] = ++id; if(son[u] == -1) return ; DFS2(son[u], T); for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == pre[u] || v == son[u]) continue; DFS2(v, v); } } int Dist(int u, int v) { int f1 = top[u], f2 = top[v]; int ans = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(u, v); swap(f1, f2); } ans += Query(1, pos[f1], pos[u]); u = pre[f1], f1 = top[u]; } if(u == v) return ans; if(dep[u] > dep[v]) swap(u, v); ans += Query(1, pos[son[u]], pos[v]); return ans; } int s[MAXN], e[MAXN], c[MAXN]; int main() { int n, S, q; while(scanf("%d%d%d", &n, &q, &S) != EOF) { init(); for(int i = 1; i <= n-1; i++) { Ri(s[i]), Ri(e[i]), Ri(c[i]); addEdge(s[i], e[i], c[i]); addEdge(e[i], s[i], c[i]); } DFS1(1, -1, 1); id = 0; DFS2(1, 1); Build(1, 1, id); for(int i = 1; i <= n-1; i++) { if(dep[s[i]] > dep[e[i]]) swap(s[i], e[i]); Update(1, pos[e[i]], c[i]); } W(q) { int op; Ri(op); int x, y; if(op == 1) { Ri(x); Ri(y); Update(1, pos[e[x]], y); } else { Ri(x); Pi(Dist(S, x)); S = x; } } } return 0; }