国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

bzoj3052糖果公園 樹上莫隊

2019-11-08 18:27:39
字體:
來源:轉載
供稿:網友

題目傳送門: http://www.lydsy.com/JudgeOnline/PRoblem.php?id=3052

最近不太想寫博客了,退役前還是寫點學的東西吧。 這個坑從我會莫隊開始就挖在這里了。。 莫隊: http://blog.csdn.net/nickwzk/article/details/52954097 可是在樹上怎么莫隊呢? 這有兩種非常妙的方法,dfs序和王室聯邦分塊(bzoj1086) 我看網上大家都用dfs序的版本,就作死寫了一個王室聯邦分塊的,然后常數巨大(大概不怪王室聯邦分塊怪我常數大 然后這個是一個樹上的帶修改的莫隊,所以當塊大小等于n23的時候復雜度最優。 借用王室聯邦分塊,另塊大小為B=n23,塊的個數為p。每個節點i屬于belong[i]。我們可以發現(belong[u], belong[v])最多p2個取值。 因為已經按塊排好序了,所以我們可以將情況分為兩種。一種是當前移動后u,v都在原塊內,那么移動總復雜度為O(B?q;另一種是u,v不在原來的塊內,那么這種情況最多出現p2次,每次移動最壞情況為O(n+n+q)。又因為n與q同階,所以可以得到總的時間復雜度為O(n53 然后在樹上移動的時候,記錄一個vis數組,到達一個點的時候將其取反,如果已經存在當前統計中就將它刪去,若沒有就將它加入。對于時間的修改可以放在移動之前也可以放在移動之后,必須要使這個操作可逆,所以修改之后要記錄下修改之前的糖果種類。 對于lca(u,v),要在記錄答案之前加上,在記錄答案之后刪去。 自帶巨大常數的Code:

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>using namespace std;const int MAXN = 100003;const int S = 17;struct Edge { int to, nxt; Edge() {} Edge(int _to, int _nxt):to(_to), nxt(_nxt) {}}e[MAXN << 1];int h[MAXN], p;int stack[MAXN], top, belong[MAXN], cnt, sz;struct Node { int l, r, id, ti; bool Operator < (const Node &x) const { return belong[l] < belong[x.l] || (belong[l] == belong[x.l] && belong[r] < belong[x.r]) || (belong[l] == belong[x.l] && belong[r] == belong[x.r] && ti < x.ti); }}q[MAXN];struct Node2 { int l, r, ti;}QQ[MAXN];int n, m, Q, Q0, Q1;int V[MAXN], W[MAXN], C[MAXN];int fa[MAXN][S + 3], dep[MAXN];long long ans[MAXN], tans;int vis[MAXN], cur[MAXN];long long sum[MAXN];int l, r, tm;inline int read() { int x = 0; char ch = getchar(); bool fg = 0; while(ch < '0' || ch > '9') { if(ch == '-') fg = 1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return fg ? -x : x;}inline void add_edge(int u, int v) { e[++p] = Edge(v, h[u]); h[u] = p; e[++p] = Edge(u, h[v]); h[v] = p;}void dfs(int u, int f) { fa[u][0] = f; dep[u] = dep[f] + 1; int bot = top; for(int i = h[u]; i; i = e[i].nxt) { int v = e[i].to; if(v == f) continue; dfs(v, u); if(top - bot >= sz) { cnt++; while(top != bot) belong[stack[top--]] = cnt; } } stack[++top] = u;}void G(int &u, int step) { for(int i = 0; i < S; i++) if((1 << i) & step) u = fa[u][i];}int lca(int u, int v) { if(dep[u] > dep[v]) swap(u, v); G(v, dep[v] - dep[u]); if(u == v) return u; for(int i = S; i >= 0; i--) if(fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } return fa[u][0];}inline void modify(int u) { tans -= V[C[u]] * sum[cur[C[u]]]; cur[C[u]] += vis[u]; vis[u] = -vis[u]; tans += V[C[u]] * sum[cur[C[u]]];}inline void update(int u, int v) { if(u == v) return; if(dep[u] > dep[v]) swap(u, v); while(dep[v] > dep[u]) { modify(v); v = fa[v][0]; } while(u != v) { modify(u); modify(v); u = fa[u][0]; v = fa[v][0]; }}inline void upd(int t) { if(vis[qq[t].l] == -1) { modify(qq[t].l); swap(C[qq[t].l], qq[t].r); modify(qq[t].l); } else swap(C[qq[t].l], qq[t].r);}inline void moveto(int u, int v) { update(l, u); update(r, v); l = u; r = v;}int main() { n = read(); m = read(); Q = read(); sz = (int)pow(n, 2.0 / 3.0); for(int i = 1; i <= m; i++) V[i] = read(); for(int i = 1; i <= n; i++) W[i] = read(); for(int i = 1, u, v; i < n; i++) { u = read(); v = read(); add_edge(u, v); } for(int i = 1; i <= n; i++) { C[i] = read(); vis[i] = 1; sum[i] = sum[i - 1] + W[i]; } for(int i = 1, tp; i <= Q; i++) { tp = read(); if(tp) { ++Q1; q[Q1].l = read(); q[Q1].r = read(); q[Q1].id = Q1; q[Q1].ti = i; } else { ++Q0; qq[Q0].l = read(); qq[Q0].r = read(); qq[Q0].ti = i; } } dfs(1, 0); while(top) belong[stack[top--]] = cnt; sort(q + 1, q + Q1 + 1); for(int k = 1; k <= S; k++) { for(int i = 1; i <= n; i++) { fa[i][k] = fa[fa[i][k - 1]][k - 1]; } } for(int i = 1; i <= Q1; i++) { if(belong[q[i].l] > belong[q[i].r]) swap(q[i].l, q[i].r); moveto(q[i].l, q[i].r); int lc = lca(l, r); modify(lc); while(qq[tm + 1].ti < q[i].ti && tm < Q0) upd(++tm); while(qq[tm].ti > q[i].ti) upd(tm--); ans[q[i].id] = tans; modify(lc); } for(int i = 1; i <= Q1; i++) printf("%lld/n", ans[i]); return 0;}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 莱西市| 沙河市| 永嘉县| 秀山| 开化县| 永丰县| 大丰市| 广汉市| 西丰县| 称多县| 中西区| 新平| 彩票| 斗六市| 乐至县| 涪陵区| 华阴市| 偃师市| 沂源县| 城固县| 措勤县| 高尔夫| 贵港市| 轮台县| 修武县| 叶城县| 清远市| 阳西县| 西和县| 蒙城县| 宝鸡市| 蒲城县| 区。| 隆回县| 南陵县| 余江县| 东平县| 奈曼旗| 涿州市| 翼城县| 舞阳县|