zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    fzuoj Problem 2177 ytaaa
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Capture the Flag
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Team Formation
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Beauty of Array
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Lunch Time
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Convert QWERTY to Dvorak
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest May Day Holiday
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Demacia of the Ancients
    zjuoj The 12th Zhejiang Provincial Collegiate Programming Contest Ace of Aces
    csuoj 1335: 高桥和低桥
  • 原文地址:https://www.cnblogs.com/soledadstar/p/11521865.html
Copyright © 2011-2022 走看看