zoukankan      html  css  js  c++  java
  • 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
    ", lastans = Ask(x, y));
        }
        return 0;
    }
  • 相关阅读:
    Apache Maven ToolChains的使用
    小师妹学JavaIO之:文件读取那些事
    JDK9的新特性:JPMS模块化
    JDK9的新特性:String压缩和字符编码
    小师妹学JavaIO之:File copy和File filter
    JDK10的新特性:var和匿名类
    Flutter 完美的验证码输入框
    Flutter 不可错过的学习资源
    《Flutter 动画系列》组合动画
    【强烈推荐】适合Flutter初学者的完整项目
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10598090.html
Copyright © 2011-2022 走看看