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 ;
}
原文地址:https://www.cnblogs.com/-maybe/p/4868126.html