题目链接:
http://codeforces.com/contest/575/problem/B
题解:
把链u,v拆成u,lca(u,v)和v,lca(u,v)(v,lca(u,v)是倒过来的)。这样就只要考虑自下而上的线性结构了,可以用前缀和的思想来做成段更新。
代码:
#include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 1e5 + 10; const int DEG = 22; const int mod = 1e9 + 7; typedef __int64 LL; struct Edge { int v, type; Edge() {} Edge(int v, int type) :v(v), type(type) {} }; int n,q; vector<Edge> egs; vector<int> G[maxn]; int dep[maxn], anc[maxn][DEG],up[maxn]; void dfs(int u,int fa) { dep[u] = dep[fa] + 1; anc[u][0] = fa; for (int i = 1; i < DEG; i++) { int f = anc[u][i - 1]; anc[u][i] = anc[f][i - 1]; } for (int i = 0; i < G[u].size(); i++) { Edge& e = egs[G[u][i]]; if (e.v == fa) continue; up[e.v] = -e.type; dfs(e.v, u); } } int cnt[2][maxn]; int Lca(int u, int v) { if (dep[u] < dep[v]) swap(u, v); for (int i = DEG - 1; i >= 0; i--) { if (dep[anc[u][i]]>=dep[v]) { u = anc[u][i]; } } if (u == v) return u; for (int i = DEG - 1; i >= 0; i--) { if (anc[u][i] != anc[v][i]) { u = anc[u][i]; v = anc[v][i]; } } //printf("u:%d,v:%d ", u, v); return anc[u][0]; } void dfs2(int u, int fa) { for (int i = 0; i < G[u].size(); i++) { Edge& e = egs[G[u][i]]; if (e.v == fa) continue; dfs2(e.v, u); cnt[0][u] += cnt[0][e.v]; cnt[1][u] += cnt[1][e.v]; } } void addEdge(int u, int v, int type) { egs.push_back(Edge(v, type)); G[u].push_back(egs.size() - 1); } LL fast_pow(int n) { LL ret = 1,x=2; while (n) { if (n & 1) ret *= x, ret %= mod; x *= x, x %= mod; n /= 2; } return ret; } void init() { for (int i = 0; i < maxn; i++) G[i].clear(); egs.clear(); memset(anc, 0, sizeof(anc)); memset(dep, 0, sizeof(dep)); memset(up, 0, sizeof(up)); memset(cnt, 0, sizeof(cnt)); } int main() { scanf("%d", &n); init(); for (int i = 0; i < n - 1; i++) { int u, v, type; scanf("%d%d%d", &u, &v, &type); if (type == 0) { addEdge(u, v, 0); addEdge(v, u, 0); } else { addEdge(u, v, 1); addEdge(v, u, -1); } } dfs(1, 0); //for (int i = 1; i <= n; i++) { // printf("%d:(%d)",i,dep[i]); // for (int j = 0; j < 20; j++) { // printf("%d ", anc[i][j]); // } // printf(" "); //} scanf("%d", &q); int s = 1, t; while (q--) { //scanf("%d%d", &s, &t); //printf("(%d,%d):%d ", s, t, Lca(s, t)); scanf("%d", &t); int lca = Lca(s, t); //printf("(%d,%d):%d ", s, t, lca); cnt[0][s]++; cnt[0][lca]--; cnt[1][t]++; cnt[1][lca]--; s = t; } dfs2(1, 0); LL ans = 0; for (int i = 1; i <= n; i++) { if (up[i] == -1) { ans += fast_pow(cnt[0][i]) - 1; ans = (ans + mod) % mod; } else if (up[i] == 1) { ans += fast_pow(cnt[1][i]) - 1; ans = (ans + mod) % mod; } } printf("%I64d ", ans); return 0; } /* 7 1 2 0 1 3 0 2 4 0 2 5 0 3 6 0 3 7 0 */