zoukankan      html  css  js  c++  java
  • 【bzoj3730】 震波

    http://www.lydsy.com/JudgeOnline/problem.php?id=3730 (题目链接)

    题意

      给出一棵树,每个节点又一个权值。两个操作,询问距离节点${x}$不超过${k}$的所有节点的权值和,将节点${x}$的权值修改为${k}$。

    Solution

      动态树分治。

      每个重心维护两个树状数组。${t[x][i]}$存重心${x}$的子树中到${parent}$的距离为${i}$的节点的权值和。${c[x][i]}$存重心${x}$的子树中到${x}$的距离为${i}$的节点的权值和。

      修改就是沿着${parent}$往上跳树状数组单点修改。

      查询考虑每次向${x}$的${parent}$跳的时候会重复计算在${x}$中的子树的节点,所以我们跳之前还要减去${x}$子树中到查询点的距离满足条件的点,这就是我们维护${t[x]}$的意义。

    细节

      树状数组要用vector,不然空间开不下,吧。。话说为什么我跑了这么久→_→

    代码

    // bzoj3730
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<ctime>
    #define LL long long
    #define inf 1ll<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
     
    const int maxn=100010;
    int head[maxn],tt[maxn],bin[30],a[maxn],par[maxn];
    int n,m,K,P;
     
    struct edge {int to,next;}e[maxn<<1];
    struct BIT {
        int l;
        vector<int> v;
        void push(int x,int val) {
            if (l<x+1) v.push_back(val),l++;
            else v[x]+=val;
        }
        int lowbit(int x) {
            return x&-x;
        }
        int sum(int x) {
            int s=0;
            for (int i=x;i;i-=lowbit(i)) s+=v[i];
            return s;
        }
        void add(int x,int val) {
            for (int i=x;i<=l;i+=lowbit(i)) v[i]+=val;
        }
        void Init() {
            for (int i=0;i<l;i++) tt[i+1]=v[i],v[i]=0;
            v.push_back(0);
            for (int i=1;i<=l;i++) add(i,tt[i]);
        }
    }c[maxn],t[maxn];
     
    namespace LittleTrick {
        int fa[maxn][30],deep[maxn],cnt;
         
        void link(int u,int v) {
            e[++cnt]=(edge){v,head[u]};head[u]=cnt;
            e[++cnt]=(edge){u,head[v]};head[v]=cnt;
        }
        void dfs(int x) {
            for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
            for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
                    fa[e[i].to][0]=x;
                    deep[e[i].to]=deep[x]+1;
                    dfs(e[i].to);
                }
        }
        int lca(int x,int y) {
            if (deep[x]<deep[y]) swap(x,y);
            int t=deep[x]-deep[y];
            for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
            for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
            return x==y ? x : fa[x][0];
        }
        int dis(int x,int y) {
            return deep[x]+deep[y]-2*deep[lca(x,y)];
        }
    }
    using namespace LittleTrick;
     
    namespace NodeDivide {
        int f[maxn],size[maxn],vis[maxn];
        int Dargen,sum;
         
        void caldargen(int x,int fa) {
            f[x]=0;size[x]=1;
            for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
                    caldargen(e[i].to,x);
                    f[x]=max(f[x],size[e[i].to]);
                    size[x]+=size[e[i].to];
                }
            f[x]=max(f[x],sum-size[x]);
            if (f[x]<f[Dargen]) Dargen=x;
        }
        void caldeep(int x,int fa,int p,int op) {
            if (op==0) t[p].push(dis(x,par[p]),a[x]);
            else c[p].push(dis(x,p),a[x]);
            for (int i=head[x];i;i=e[i].next)
                if (e[i].to!=fa && !vis[e[i].to]) caldeep(e[i].to,x,p,op);
        }
        void work(int x) {
            vis[x]=1;
            caldeep(x,0,x,1);
            for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
                    Dargen=0;sum=size[e[i].to];
                    caldargen(e[i].to,x);
                    par[Dargen]=x;
                    t[Dargen].push(0,0);
                    caldeep(e[i].to,x,Dargen,0);
                    work(Dargen);
                }
            t[x].Init();c[x].Init();
        }
        void Init() {
            f[Dargen=0]=inf;sum=n;
            caldargen(1,0);
            t[Dargen].push(0,0);
            work(Dargen);
        }
    }
    using namespace NodeDivide;
     
    namespace Query {
        void modify(int x,int val) {
            for (int i=x;i;i=par[i]) {
                int d1=dis(x,par[i]),d2=dis(x,i);
                c[i].add(d2+1,-a[x]);c[i].add(d2+1,val);
                t[i].add(d1+1,-a[x]);t[i].add(d1+1,val);
            }
            a[x]=val;
        }
        int query(int x) {
    		int dx=dis(x,P);
    		int dp=dis(par[x],P);
    		int res=dx<=K ? c[x].sum(min(c[x].l,K-dx+1)) : 0;
    		if (!par[x]) return res;
    		if (dp<=K) res-=t[x].sum(min(t[x].l,K-dp+1));
    		return res+query(par[x]);
        }
    }
    using namespace Query;
     
    int main() {
        bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int u,v,i=1;i<n;i++) {
            scanf("%d%d",&u,&v);
            link(u,v);
        }
        dfs(1);
        Init();
        int ans=0;
        for (int op,i=1;i<=m;i++) {
            scanf("%d%d%d",&op,&P,&K);
            P^=ans,K^=ans;
            if (op==0) printf("%d
    ",ans=query(P));
            else modify(P,K);
        }
        return 0;
    }
    
  • 相关阅读:
    训练总结
    图论--最短路--SPFA模板(能过题,真没错的模板)
    图论--最短路-- Dijkstra模板(目前见到的最好用的)
    The 2019 Asia Nanchang First Round Online Programming Contest B Fire-Fighting Hero(阅读理解)
    关于RMQ问题的四种解法
    The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 K题 center
    The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 XKC's basketball team
    The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 D Carneginon
    ZOJ 3607 Lazier Salesgirl (枚举)
    ZOJ 3605 Find the Marble(dp)
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6359206.html
Copyright © 2011-2022 走看看