Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 6245 | Accepted: 1704 |
Description
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE i v | Change the weight of the ith edge to v |
NEGATE a b | Negate the weight of every edge on the path from a to b |
QUERY a b | Find the maximum weight of edges on the path from a to b |
Input
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with
weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE
” ends the test case.
Output
For each “QUERY
” instruction, output the result on a separate line.
Sample Input
1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE
Sample Output
13
题意:给你一个N个点的树和各边的权值。现在有三个操作1,CHANGE i v 表示修改第i条边的边权;2 NEGATE a b 表示将a点到b点路径上所有边的边权变为原来的相反数;3,QUERY a b 表示查询a点到b点路径上最大边权值。
思路:LCA转RMQ算法直接可以KO,在find_depth()记录点i的前驱pre[i]。
对于操作1,CHANGE i v —— 直接修改边权即可。
对于操作2和操作3,难点在于查询路径上边的编号。我们可以一步步查询点i和它前驱pre[i]的路径,关于这点详看代码。
AC代码:2032ms
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 10000+10 #define MAXM 20000+10 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, val, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int id[MAXN]; int vs[MAXN<<1], depth[MAXN<<1]; int pre[MAXN];//记录前驱 int dfs_clock; int N; 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() { init(); int a, b, c; scanf("%d", &N); 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) { 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; pre[v] = u; DFS(v, u, d+1); vs[dfs_clock] = u; depth[dfs_clock++] = d; } } void find_depth() { memset(vs, 0, sizeof(vs)); memset(id, 0, sizeof(id)); memset(depth, 0, sizeof(depth)); memset(pre, 0, sizeof(pre)); dfs_clock = 1; DFS(1, -1, 0); } int dp[MAXN<<1][30]; void RMQ_init(int NN) { 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 a, int b) { int u = id[a]; int v = id[b]; if(u < v) return vs[query(u, v)]; else return vs[query(v, u)]; } int findedge(int u, int v)//找u -> v这条边的编号 { for(int i = head[u]; i != -1; i = edge[i].next) { if(edge[i].to == v) return i; } } void work(int u, int e1, int e2) { int next; int node;//要修改的边 编号 next = e1; while(next != u) { node = findedge(next, pre[next]); edge[node].val = edge[node^1].val = -edge[node].val; next = pre[next]; } next = e2; while(next != u) { node = findedge(next, pre[next]); edge[node].val = edge[node^1].val = -edge[node].val; next = pre[next]; } } int ans; void Find(int u, int e1, int e2) { int next; int node;//要查询的边 编号 next = e1; while(next != u) { node = findedge(next, pre[next]); ans = max(ans, edge[node].val); next = pre[next]; } next = e2; while(next != u) { node = findedge(next, pre[next]); ans = max(ans, edge[node].val); next = pre[next]; } } void solve() { find_depth(); RMQ_init(dfs_clock-1); char str[10]; int lca, a, b; while(scanf("%s", str), strcmp(str, "DONE")) { scanf("%d%d", &a, &b); if(str[0] == 'C') { a = a*2 - 1;//醉了一开始这里用位运算没加括号。。。 edge[a].val = edge[a^1].val = b; } else if(str[0] == 'N') { lca = LCA(a, b); work(lca, a, b); } else { lca = LCA(a, b); ans = -INF; Find(lca, a, b); printf("%d\n", ans); } } } int main() { int t; scanf("%d", &t); while(t--) { getMap(); 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 (10000+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, Min, Max, lazy; }; Tree tree[MAXN<<2]; void PushUp(int o){ tree[o].Max = max(tree[ll].Max, tree[rr].Max); tree[o].Min = min(tree[ll].Min, tree[rr].Min); } void PushDown(int o) { if(tree[o].lazy == -1) { tree[ll].lazy *= -1; tree[rr].lazy *= -1; int Max = tree[ll].Max, Min = tree[ll].Min; tree[ll].Min = -Max; tree[ll].Max = -Min; Max = tree[rr].Max; Min = tree[rr].Min; tree[rr].Min = -Max; tree[rr].Max = -Min; tree[o].lazy = 1; } } void Build(int o, int l, int r) { tree[o].l = l; tree[o].r = r; tree[o].Max = tree[o].Min = 0; tree[o].lazy = 1; if(l == r) return ; int mid = (l + r) >> 1; Build(lson); Build(rson); } void Negate(int o, int L, int R) { if(tree[o].l == L && tree[o].r == R) { int Min = tree[o].Min, Max = tree[o].Max; tree[o].Max = -Min; tree[o].Min = -Max; tree[o].lazy *= -1; return ; } PushDown(o); int mid = (tree[o].l + tree[o].r) >> 1; if(R <= mid) Negate(ll, L, R); else if(L > mid) Negate(rr, L, R); else {Negate(ll, L, mid); Negate(rr, mid+1, R);} PushUp(o); } void Update(int o, int pos, int v) { if(tree[o].l == tree[o].r) { tree[o].Max = tree[o].Min = v; return ; } PushDown(o); 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].Max; PushDown(o); 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 max(Query(ll, L, mid), Query(rr, mid+1, R)); } struct Edge{ int from, to, val, next; }; Edge edge[MAXN<<1]; int head[MAXN], edgenum; int s[MAXN], e[MAXN], c[MAXN]; 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 GetMax(int u, int v) { int f1 = top[u], f2 = top[v]; int ans = -INF; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(u, v); swap(f1, f2); } ans = max(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); return max(ans, Query(1, pos[son[u]], pos[v])); } void Change(int u, int v) { int f1 = top[u], f2 = top[v]; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(u, v); swap(f1, f2); } Negate(1, pos[f1], pos[u]); u = pre[f1], f1 = top[u]; } if(u == v) return ; if(dep[u] > dep[v]) swap(u, v); Negate(1, pos[son[u]], pos[v]); } int main() { int t; Ri(t); W(t) { int n; Ri(n); 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]); } char str[10]; while(Rs(str), strcmp(str, "DONE")) { int x, y; Ri(x); Ri(y); if(str[0] == 'Q') Pi(GetMax(x, y)); else if(str[0] == 'C') Update(1, pos[e[x]], y); else Change(x, y); } } return 0; }