zoukankan      html  css  js  c++  java
  • HDU 5044 Tree 树链剖分

    一棵树,初始边权和点权都为0

    现在有m个操作,每一个操作:

    ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k. 

    ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k. 

    操作完后,输出每一个点的点权和每一条边的边权(边权按照输入顺序输出)

    我们把边权也当做点权处理

    这道题本来是一道痕裸的树链剖分的题目,用树状数组维护就可以了O(nlogn*logn)

    不过这样会T,因为出题人特意卡了常数

    有人是加了一个输入输出外挂过的

    不过这道题有更好的做法

    我们在树链剖分后的数组用标记法,每次对一个连续区间+k时,我们对位置L标记+k,对位置R+1标记-k

    最后从前往后加一遍就是了

    O(nlogn)

    注意:处理边权和点权时,对lca的处理是不同的

    点权时,lca的点权也要更新

    边权时,lca对应的边的边权时不需要更新的

    注意2:当节点个数为1时,是没有边的,也就没有边权了,但是输出的时候我们边权这一行依然要输出,是一个空行

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    
    #define LL long long
    #define pb push_back
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    
    using namespace std;
    
    const int maxn=1e5+10;
    
    int dep[maxn];
    int siz[maxn];
    int chg[maxn];
    int fa[maxn];
    int son[maxn];
    int top[maxn];
    LL c[2][maxn];
    int n;
    int e[maxn][2];
    
    struct Edge
    {
        int to,next;
    };
    Edge edge[maxn<<1];
    int head[maxn];
    int tot;
    
    void init()
    {
        memset(head,-1,sizeof head);
        tot=0;
    }
    
    void addedge(int u,int v)
    {
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    void solve(int );
    
    int main()
    {
        int test;
        int cas=1;
        scanf("%d",&test);
        while(test--){
            printf("Case #%d:
    ",cas++);
            init();
            int q;
            scanf("%d %d",&n,&q);
            for(int i=1;i<n;i++){
                scanf("%d %d",&e[i][0],&e[i][1]);
                addedge(e[i][0],e[i][1]);
                addedge(e[i][1],e[i][0]);
            }
            solve(q);
        }
        return 0;
    }
    
    void dfs0(int u,int pre)
    {
        dep[u]=dep[pre]+1;
        fa[u]=pre;
        siz[u]=1;
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].to;
            if(v==pre)
                continue;
            dfs0(v,u);
            siz[u]+=siz[v];
            if(son[u]==-1 || siz[v]>siz[son[u]])
                son[u]=v;
        }
    }
    
    void dfs1(int u,int tp)
    {
        top[u]=tp;
        chg[u]=++tot;
        if(son[u]==-1)
            return ;
        dfs1(son[u],tp);
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].to;
            if(v==fa[u] || v==son[u])
                continue;
            dfs1(v,v);
        }
    }
    
    void update_path(int a,int b,int cnt,int k)
    {
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])
                swap(a,b);
            c[cnt][chg[top[a]]]+=k;
            c[cnt][chg[a]+1]-=k;
            a=fa[top[a]];
        }
        if(dep[a]<dep[b])
            swap(a,b);
        if(cnt==1){
            c[cnt][chg[b]]+=k;
            c[cnt][chg[a]+1]-=k;
        }
        else{
            c[cnt][chg[b]+1]+=k;
            c[cnt][chg[a]+1]-=k;
        }
        return ;
    }
    
    void solve(int q)
    {
        memset(c,0,sizeof c);
        memset(dep,0,sizeof dep);
        memset(son,-1,sizeof son);
    
        dfs0(1,1);
        tot=0;
        dfs1(1,1);
    
        for(int i=1;i<=q;i++){
            char str[10];
            scanf("%s",str);
            int u,v,k;
            scanf("%d %d %d",&u,&v,&k);
            if(str[3]=='1'){
                update_path(u,v,1,k);
            }
            else{
                update_path(u,v,0,k);
            }
        }
    
        for(int i=1;i<=n;i++){
            c[0][i]+=c[0][i-1];
            c[1][i]+=c[1][i-1];
        }
        for(int i=1;i<=n;i++){
            printf("%d",c[1][chg[i]]);
            if(i<n)
                printf(" ");
            else
                puts("");
        }
        for(int i=1;i<n;i++){
            int cur=e[i][0];
            if(dep[e[i][0]]<dep[e[i][1]])
                cur=e[i][1];
            printf("%d",c[0][chg[cur]]);
            if(i<n-1)
                printf(" ");
        }
        puts("");
        return ;
    }
  • 相关阅读:
    MyCat简介+Mybatis实现多租户(链接)
    mybatis的sql执行过程底层源码分析和缓存原理分析
    推荐算法数据集
    CentOS系统初始化
    NAT
    VRRP
    BGP协议的原理及应用
    ospf协议的重分发
    静态路由的原理与配置、动态路由
    OSPF (企业内部使用的动态路由协议)
  • 原文地址:https://www.cnblogs.com/-maybe/p/4868126.html
Copyright © 2011-2022 走看看