3730: 震波
3730: 震波
鏈接
分析:
動態點分治。
求距離小于等于k的點權和。
建出點分樹,然后對于每個分治中心,維護連通塊到這個點的所有距離,因為要容斥掉多計算的,所以在維護這個點到這個分治中心在點分樹的父節點的距離。
動態開點線段樹,下標為距離,記錄權值和。
空間復雜福:$nlog^2n$,時間復雜度$nlog^2n$。加上大常數后,跑的有點慢,加上fread后,14904ms卡過。
代碼:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #include<bitset> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL;char buf[100000], *p1 = buf, *p2 = buf; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) inline int read() {int x=0,f=1;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-1;for(;isdigit(ch);ch=nc())x=x*10+ch-'0';return x*f; }const int N = 100005; struct Edge { int to, nxt; } e[N << 1]; int head[N], dep[N], f[N << 1][20], Log[N << 1], pos[N], siz[N], val[N], fa[N]; int En, Index, TreeIndex, Mn, Root, n; bool vis[N]; int sum[N * 200], ls[N * 200], rs[N * 200], Ra[N], Rb[N];inline void add_edge(int u,int v) {++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En; } void update(int l,int r,int &now,int p,int v) {if (!now) now = ++TreeIndex;sum[now] += v;if (l == r) return ;int mid = (l + r) >> 1;if (p <= mid) update(l, mid, ls[now], p, v);else update(mid + 1, r, rs[now], p, v); } int query(int l,int r,int now,int p) {if (!now) return 0;if (l == r) return sum[now];int mid = (l + r) >> 1;if (p <= mid) return query(l, mid, ls[now], p);else return query(mid + 1, r, rs[now], p) + sum[ls[now]]; } void predfs(int u,int fa) {pos[u] = ++Index; f[Index][0] = dep[u];fore (i, u, v) if (v != fa) dep[v] = dep[u] + 1, predfs(v, u), f[++Index][0] = dep[u]; } void prermq() {for (int i = 2; i <= Index; ++i) Log[i] = Log[i >> 1] + 1;for (int j = 1; j <= Log[Index]; ++j)for (int i = 1; i + (1 << j) - 1 <= Index; ++i)f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); } int LCA(int x,int y) {x = pos[x], y = pos[y];if (x > y) swap(x, y);int k = Log[y - x + 1];return min(f[x][k], f[y - (1 << k) + 1][k]); } int getdis(int x,int y) { return dep[x] + dep[y] - 2 * LCA(x, y); }void getroot(int u,int fa,int Size) {int mx = 0; siz[u] = 1;fore (i, u, v)if (!vis[v] && v != fa) getroot(v, u, Size), siz[u] += siz[v], mx = max(mx, siz[v]);mx = max(mx, Size - siz[u]);if (mx < Mn) Mn = mx, Root = u; } void work(int u,int pre,int r) {update(0, n - 1, Ra[r], getdis(u, r), val[u]); if (fa[r]) update(0, n - 1, Rb[r], getdis(u, fa[r]), val[u]);siz[u] = 1;fore (i, u, v) if (!vis[v] && v != pre) work(v, u, r), siz[u] += siz[v]; } void solve(int u) {work(u, 0, u); vis[u] = 1; fore (i, u, v) if (!vis[v]) Mn = 1e9, getroot(v, u, siz[v]), fa[Root] = u, solve(Root); } void Change(int x,int y) {for (int i = x; i; i = fa[i]) {update(0, n - 1, Ra[i], getdis(x, i), y - val[x]);if (fa[i]) update(0, n - 1, Rb[i], getdis(x, fa[i]), y - val[x]);}val[x] = y; } int Ask(int x,int k) {LL ans = 0;for (int i = x; i; i = fa[i]) {if (getdis(i, x) <= k) ans += query(0, n - 1, Ra[i], k - getdis(x, i));if (fa[i] && getdis(x, fa[i]) <= k) ans -= query(0, n - 1, Rb[i], k - getdis(x, fa[i]));}return ans; } int main() {n = read();int m = read();for (int i = 1; i <= n; ++i) val[i] = read();for (int i = 1; i < n; ++i) add_edge(read(), read());predfs(1, 0); prermq();Mn = 1e9, getroot(1, 0, n);solve(Root); int opt, x, y, lastans = 0;while (m --) {opt = read(), x = read() ^ lastans, y = read() ^ lastans;if (opt) Change(x, y);else printf("%d\n", lastans = Ask(x, y));}return 0; }?
轉載于:https://www.cnblogs.com/mjtcn/p/10598090.html
總結
- 上一篇: 广东利是习俗
- 下一篇: Mplus—纵向不变性/纵向等值