• Luogu P3833 [SHOI2012]魔法树


    此题理论最优解

    题目链接

    题目大意:路径修改,子树求和

    明显是树剖的模板,但树剖的时间复杂度达了优秀的$Theta(Q ;log^2n)$,而实际上树上差分可以把时间复杂度降到$Theta(Q ;logn)$。

    设$tag[x]$为$1$到$x$的路径上全都加了这个值,显然对于$(x,y)$这条路径加$d$的操作可以看作
    $$tag[x]+=d,tag[y]+=d,tag[LCA(x,y)]-=d,tag[prt[LCA(x,y)]]-=d$$

    若查询以$root$为根的子树和,考虑子树内每个点$x$对答案的贡献是
    $$(dep[x]-dep[root]+1) imes tag[x]$$
    上式的意义是在$(x,root)$这条路径每个点都被加了$tag[x]$,对上式求和得到
    $$sum ;((dep[x]-dep[root]+1) imes tag[x])$$
    $$sum ;(dep[x] imes tag[x]-(dep[root]-1) imes tag[x])$$
    $$sum ;(dep[x] imes tag[x])-(dep[root]-1) imessum;(tag[x])$$

    两个树状数组维护$dep[x] imes tag[x]$和$tag[x]$就好了,因为在$DFS$序上子树是连续的区间,直接查询即可。

    因为我的丑代码常数太大,把理论最优解跑还得不如树剖

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    inline int read() {
        char ch;
        bool bj=0;
        while(!isdigit(ch=getchar()))
            bj|=(ch=='-');
        int res=ch^(3<<4);
        while(isdigit(ch=getchar()))
            res=(res<<1)+(res<<3)+(ch^(3<<4));
        return bj?-res:res;
    }
    void printnum(int x) {
        if(x>9)printnum(x/10);
        putchar(x%10+'0');
    }
    inline void print(int x,char ch) {
        if(x<0) {
            putchar('-');
            x=-x;
        }
        printnum(x);
        putchar(ch);
    }
    const int MAXN=1e5+5;
    int n,m,h[MAXN],cnt;
    int top[MAXN],size[MAXN],prt[MAXN],son[MAXN],dep[MAXN],tot,tid[MAXN];
    struct Edge {
        int to,nxt;
    } w[MAXN<<1];
    int c1[MAXN],c2[MAXN];
    inline void AddEdge(int x,int y) {
        w[++cnt].nxt=h[x];
        w[cnt].to=y;
        h[x]=cnt;
    }
    void DFS1(int x,int fa,int depth) {
        dep[x]=depth;
        prt[x]=fa;
        size[x]=1;
        for(int i=h[x]; i; i=w[i].nxt) {
            int v=w[i].to;
            if(v==fa)continue;
            DFS1(v,x,depth+1);
            if(size[v]>size[son[x]])son[x]=v;
            size[x]+=size[v];
        }
    }
    void DFS2(int x,int sp) {
        top[x]=sp;
        tid[x]=++tot;
        if(!son[x])return;
        DFS2(son[x],sp);
        for(int i=h[x]; i; i=w[i].nxt) {
            int v=w[i].to;
            if(v==prt[x]||v==son[x])continue;
            DFS2(v,v);
        }
    }
    inline int LCA(int x,int y) {
        while(top[x]^top[y]) {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=prt[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        return x;
    }
    inline int lowbit(int x) {
        return x&(-x);
    }
    inline void update(int x,int d,int c[]) {
        if(!x)return;
        while(x<=n)c[x]+=d,x+=lowbit(x);
    }
    inline int query(int x,int c[]) {
        int sum=0;
        while(x)sum+=c[x],x-=lowbit(x);
        return sum;
    }
    inline void add(int x,int d) {
        update(tid[x],d,c1);
        update(tid[x],dep[x]*d,c2);
    }
    inline int ask(int x,int y,int c[]) {
        return query(y,c)-query(x-1,c);
    }
    signed main() {
        n=read();
        int x,y,d;
        for(int i=1; i<n; i++) {
            x=read()+1;
            y=read()+1;
            AddEdge(x,y);
            AddEdge(y,x);
        }
        DFS1(1,0,1);
        DFS2(1,1);
        m=read();
        char ch;
        while(m--) {
            do ch=getchar();
            while(ch!='A'&&ch!='Q');
            if(ch=='A') {
                x=read()+1;
                y=read()+1;
                d=read();
                int u=LCA(x,y);
                add(x,d);
                add(y,d);
                add(u,-d);
                add(prt[u],-d);
            } else {
                x=read()+1;
                int tmp=ask(tid[x],tid[x]+size[x]-1,c1);
                print(ask(tid[x],tid[x]+size[x]-1,c2)-tmp*(dep[x]-1),'
    ');
            }
        }
        return 0;
    }


    为什么还是写了两个DFS?因为我要树剖求LCA

  • 相关阅读:
    [BZOJ1625][Usaco2007 Dec]宝石手镯
    [BZOJ1699][Usaco2007 Jan]Balanced Lineup排队
    [BZOJ1606][Usaco2008 Dec]Hay For Sale 购买干草
    [BZOJ1610][Usaco2008 Feb]Line连线游戏
    [BZOJ1609][Usaco2008 Feb]Eating Together麻烦的聚餐
    [BZOJ1602][Usaco2008 Oct]牧场行走
    [BZOJ1601][Usaco2008 Oct]灌水
    [BZOJ1607][Usaco2008 Dec]Patting Heads 轻拍牛头
    [BZOJ1579][Usaco2008 Mar]土地购买
    HDU 4248 A Famous Stone Collector 组合数学dp ****
  • 原文地址:https://www.cnblogs.com/soledadstar/p/11521865.html
Copyright © 2020-2023  润新知