[动态树分治]
最近学习了一下动态树分治。刷了一些比较基础的题目
一般都是存一下到这个重心的信息,然后再存这棵子树到上一层重心的信息,搞一搞就可以了
[COGS 2278]树黑白
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 200010 using namespace std; typedef long long ll; int n, m; //-------------------------------------------------// struct Edge{int to, nxt, dis;}edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v, int d){ cnt ++; edge[cnt].to = v; edge[cnt].nxt = h[u]; edge[cnt].dis = d; h[u] = cnt; } //-------------------------------------------------// ll dis[maxn]; int dep[maxn], fa[maxn], anc[maxn][20]; void dfs(int u){ dep[u] = dep[fa[u]] + 1; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; dis[v] = dis[u] + edge[i].dis; fa[v] = u; dfs(v); } } int ask_LCA(int p, int q){ if(dep[p] < dep[q])swap(p, q); int log = 1; for(; 1 << log <= dep[p]; log ++); log --; for(int i = log; i >= 0; i --) if(anc[p][i] && dep[anc[p][i]] >= dep[q]) p = anc[p][i]; if(p == q)return p; for(int i = log; i >= 0; i --) if(anc[p][i] && anc[p][i] != anc[q][i]) p = anc[p][i], q = anc[q][i]; return fa[p]; } ll dist(int p, int q){return dis[p] + dis[q] - 2 * dis[ask_LCA(p, q)];} //-------------------------------------------------// int g[maxn], size[maxn], G, Sum; bool vis[maxn], check[maxn]; void Get_G(int u, int fa){ size[u] = 1; int f = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v])continue; Get_G(v, u); size[u] += size[v]; f = max(f, size[v]); } f = max(f, Sum - size[u]); if((f << 1) <= Sum)G = u; } void Divide(int u, int f){ g[u] = f; vis[u] = true; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; Sum = size[v], G = v; Get_G(v, u); Divide(G, u); } } //-------------------------------------------------// ll Node[maxn], Dis[maxn], Disf[maxn], ans; int Standard; void White(int u){ Node[u] --; Dis[u] -= dist(u, Standard); if(g[u] == -1)return; Disf[u] -= dist(g[u], Standard); White(g[u]); } void Black(int u){ Node[u] ++; Dis[u] += dist(u, Standard); if(g[u] == -1)return; Disf[u] += dist(g[u], Standard); Black(g[u]); } void ask(int u){ ans += (Node[u] * dist(u, Standard) + Dis[u]); if(g[u] == -1)return; ans -= (Node[u] * dist(g[u], Standard) + Disf[u]); ask(g[u]); } int main(){ freopen("A_Tree.in", "r", stdin); freopen("A_Tree.out", "w", stdout); scanf("%d%d", &n, &m); int u, v, d; for(int i = 1; i < n; i ++){ scanf("%d%d%d", &u, &v, &d); add(u, v, d), add(v, u, d); } dfs(1); Sum = n; Get_G(1, -1), Divide(G, -1); for(int i = 1; i <= n; i ++) anc[i][0] = fa[i]; for(int j = 1; 1 << j <= n; j ++) for(int i = 1; i <= n; i ++) anc[i][j] = anc[anc[i][j-1]][j-1]; char cmd[2]; while(m --){ scanf("%s%d", cmd, &u); Standard = u; if(cmd[0] == 'Q'){ ans = 0; ask(u); printf("%lld\n", ans); } else{ if(check[u])White(u); else Black(u); check[u] ^= 1; } } return 0; }
[COGS 2258]复仇的序幕曲
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #define maxn 100010 using namespace std; struct Edge{int to, nxt, dis;}edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v, int d){ cnt ++; edge[cnt].to = v; edge[cnt].nxt = h[u]; edge[cnt].dis = d; h[u] = cnt; } int n, m, a[maxn]; int dis[maxn], fa[maxn], anc[maxn][20], dep[maxn]; void dfs(int u){ dep[u] = dep[fa[u]] + 1; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; fa[v] = u; dis[v] = dis[u] + edge[i].dis; dfs(v); } } int ask_LCA(int p, int q){ if(dep[p] < dep[q])swap(p, q); int log = 1; for(; 1 << log <= dep[p]; log ++); log --; for(int i = log; i >= 0; i --) if(anc[p][i] && dep[anc[p][i]] >= dep[q]) p = anc[p][i]; if(p == q)return p; for(int i = log; i >= 0; i --) if(anc[p][i] && anc[p][i] != anc[q][i]) p = anc[p][i], q = anc[q][i]; return fa[p]; } int dist(int p, int q){ return dis[p] + dis[q] - 2 * dis[ask_LCA(p, q)]; } //-----------------------------------------------// bool vis[maxn]; int g[maxn], size[maxn], G, Sum; vector<pair<int, int> > V[maxn], F[maxn]; void Get_G(int u, int fa){ int f = 0; size[u] = 1; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v] || v == fa)continue; Get_G(v, u); size[u] += size[v]; f = max(f, size[v]); } f = max(f, Sum - size[u]); if((f << 1) <= Sum) G = u; } void Divide(int u, int f){ g[u] = f, vis[u] = true; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; Sum = size[v], G = v; Get_G(v, u), Divide(G, u); } } int st, T, ans; void update(int u){ V[u].push_back(make_pair(dist(st, u), a[st])); F[u].push_back(make_pair(dist(st, g[u]), a[st])); if(g[u] > 0)update(g[u]); } int Binarysearch(vector<pair<int, int> > &V, int nw){ if(V[0].first > nw)return 0; int l = 0, r = V.size() - 1; while(l < r){ int m = l + (r - l + 1) / 2; if(V[m].first > nw) r = m - 1; else l = m; } return V[l].second; } void ask(int u){ ans += Binarysearch(V[u], T - dist(u, st)); if(g[u] == -1)return; int d = dist(g[u], st); ans -= Binarysearch(F[u], T - d); ask(g[u]); } //-----------------------------------------------// int main(){ freopen("SS.in", "r", stdin); freopen("SS.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); int u, v, d; for(int i = 1; i < n; i ++){ scanf("%d%d%d", &u, &v, &d); add(u, v, d), add(v, u, d); } dfs(1); for(int i = 1; i <= n; i ++) anc[i][0] = fa[i]; for(int j = 1; 1 << j <= n; j ++) for(int i = 1; i <= n; i ++) anc[i][j] = anc[anc[i][j-1]][j-1]; Sum = n; Get_G(1, -1), Divide(G, -1); for(int i = 1; i <= n; i ++) st = i, update(i); int sum = 0; for(int i = 1; i <= n; i ++){ sort(V[i].begin(), V[i].end()); sort(F[i].begin(), F[i].end()); sum = 0; for(int j = 0; j < V[i].size(); j ++){ sum += V[i][j].second; V[i][j].second = sum; } sum = 0; for(int j = 0; j < F[i].size(); j ++){ sum += F[i][j].second; F[i][j].second = sum; } } while(m --){ scanf("%d%d", &st, &T); ans = 0, ask(st); printf("%d\n", ans); } return 0; }
[HNOI 2015]开店
并不清楚为什么要写G=v;这句话,难道找不到么。。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #define maxn 150010 using namespace std; typedef long long ll; typedef vector<pair<int, ll> > vp; int n, Q, A; struct Edge{int to, nxt, dis;}edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v, int w){ cnt ++; edge[cnt].to = v; edge[cnt].nxt = h[u]; edge[cnt].dis = w; h[u] = cnt; } int a[maxn]; //-----------------------------------------------------// int dep[maxn], fa[maxn], anc[maxn][20]; ll dis[maxn]; void dfs(int u){ dep[u] = dep[fa[u]] + 1; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; fa[v] = u; dis[v] = dis[u] + edge[i].dis; dfs(v); } } void pre_LCA(){ for(int i = 1; i <= n; i ++) anc[i][0] = fa[i]; for(int j = 1; 1 << j <= n; j ++) for(int i = 1; i <= n; i ++) anc[i][j] = anc[anc[i][j-1]][j-1]; } int ask_LCA(int p, int q){ if(dep[p] < dep[q])swap(p, q); int log = 1; for(; 1 << log <= dep[p]; log ++); log --; for(int i = log; i >= 0; i --) if(anc[p][i] && dep[anc[p][i]] >= dep[q]) p = anc[p][i]; if(p == q)return p; for(int i = log; i >= 0; i --) if(anc[p][i] && anc[p][i] != anc[q][i]) p = anc[p][i], q = anc[q][i]; return fa[p]; } ll dist(int u, int v){ return dis[u] + dis[v] - 2 * dis[ask_LCA(u, v)]; } //-----------------------------------------------------// int g[maxn], size[maxn], G, Sum; vp V[maxn], F[maxn]; bool vis[maxn]; void Get_G(int u, int fa){ size[u] = 1; int f = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v])continue; Get_G(v, u); size[u] += size[v]; f = max(f, size[v]); } f = max(f, Sum - size[u]); if((f << 1) <= Sum)G = u; } void Divide(int u, int f){ g[u] = f, vis[u] = true; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; Sum = size[v], G = v; Get_G(v, u), Divide(G, u); } } int St; void update(int u){ V[u].push_back(make_pair(a[St], dist(St, u))); if(g[u] < 0) return; F[u].push_back(make_pair(a[St], dist(St, g[u]))); update(g[u]); } ll ans = 0; int L, R; int Bs(vp& V, ll nw){ int l = 0, r = V.size() - 1; while(l < r){ int m = l + (r - l + 1) / 2; if(V[m].first <= nw)l = m; else r = m - 1; } return l; } ll Binarysearch(vp &V, ll dis){ if(V[0].first > R)return 0; if(V[V.size()-1].first < L)return 0; int ret1 = Bs(V, L-1), ret2 = Bs(V, R); return dis * (ret2 - ret1) + V[ret2].second - V[ret1].second; } void ask(int u){ ans += Binarysearch(V[u], dist(St, u)); if(g[u] < 0)return; ans -= Binarysearch(F[u], dist(St, g[u])); ask(g[u]); } int main(){ freopen("shop_hnoi2015.in", "r", stdin); freopen("shop_hnoi2015.out", "w", stdout); scanf("%d%d%d", &n, &Q, &A); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); int u, v, d; for(int i = 1; i < n; i ++){ scanf("%d%d%d", &u, &v, &d); add(u, v, d), add(v, u, d); } dfs(1), pre_LCA(), Sum = n; Get_G(1, -1), Divide(G, -1); for(int i = 1; i <= n; i ++) update(St = i); for(int i = 1; i <= n; i ++){ V[i].push_back(make_pair(-1, 0)); F[i].push_back(make_pair(-1, 0)); sort(V[i].begin(), V[i].end()); sort(F[i].begin(), F[i].end()); for(int j = 1; j < V[i].size(); j ++) V[i][j].second += V[i][j-1].second; for(int j = 1; j < F[i].size(); j ++) F[i][j].second += F[i][j-1].second; } while(Q --){ scanf("%d%d%d", &u, &L, &R); L = (L + ans) % A, R = (R + ans) % A; if(L > R)swap(L, R); St = u, ans = 0, ask(u); printf("%lld\n", ans); } return 0; }
给时光以生命,而不是给生命以时光。