HDU 5044 Tree --树链剖分

题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出。

解法:树链剖分可做,剖出来如果直接用线段树来区间更新的话会TLE,所以要换一种姿势,有一种树链剖分的经典姿势就是看做树状数组一样,每次加值的时候,比如u->v之间加一个值k,那么在u处+k,v+1处-k即可,然后扫一遍,每次把当前位置要做的操作做完,此时总共加的值就是当前处的值,扫一遍的时候维护的是前缀的和,也就是两个ans不清零。

这题卡时间太紧,不加读入挂会T,不加输出挂的话跑4921ms,也是飘过,加了输入输出挂才稍微好点,4687ms,可能是树链剖分不够优越

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define lll __int64
using namespace std;
#define N 100007

int siz[N];  //子树大小
int son[N];  //重儿子
int dep[N];  //深度
int pos[N],apos[N];  //点在线段树中的位置
int Top[N];  //所在重链的祖先
int fa[N];   //父节点
lll eans[N],nans[N];  //答案
int head[2*N],tot,POS,n,m;
struct Edge
{
    int v,next;
}G[2*N],Qe[10*N],Qn[10*N];
int heade[10*N],headn[10*N],tote,totn;
struct node
{
    int u,v;
}edge[N];

void init()
{
    POS = tot = tote = totn = 0;
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
    memset(heade,-1,sizeof(heade));
    memset(headn,-1,sizeof(headn));
}

void addedge(int u,int v)
{
    G[tot].v = v, G[tot].next = head[u], head[u] = tot++;
    G[tot].v = u, G[tot].next = head[v], head[v] = tot++;
}

void ADDNedge(int u,int v)  //代替vector来存操作
{
    Qn[totn].v = v, Qn[totn].next = headn[u], headn[u] = totn++;
}

void ADDEedge(int u,int v)  //代替vector来存操作
{
    Qe[tote].v = v, Qe[tote].next = heade[u], heade[u] = tote++;
}

void dfs(int u,int f)
{
    dep[u] = dep[f]+1;
    siz[u] = 1;
    for(int i=head[u];i!=-1;i=G[i].next)
    {
        int v = G[i].v;
        if(v == f) continue;
        fa[v] = u;
        dfs(v,u);
        if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
        siz[u] += siz[v];
    }
}

void dfs2(int u,int top)
{
    pos[u] = ++POS;
    apos[POS] = u;
    Top[u] = top;
    if(son[u] != -1) dfs2(son[u],top);
    for(int i=head[u];i!=-1;i=G[i].next)
    {
        int v = G[i].v;
        if(v != fa[u] && v != son[u])
            dfs2(v,v);
    }
}

void AddEdge(int u,int v,int k)
{
    int fx = Top[u], fy = Top[v];
    while(fx != fy)
    {
        if(dep[fx] < dep[fy])
        {
            swap(u,v);
            swap(fx,fy);
        }
        ADDEedge(pos[fx],k);
        ADDEedge(pos[u]+1,-k);
        u = fa[fx];
        fx = Top[u];
    }
    if(dep[u] > dep[v]) swap(u,v);
    ADDEedge(pos[son[u]],k);
    ADDEedge(pos[v]+1,-k);
}

void AddNode(int u,int v,int k)
{
    int fx = Top[u], fy = Top[v];
    while(fx != fy)
    {
        if(dep[fx] < dep[fy])
        {
            swap(u,v);
            swap(fx,fy);
        }
        ADDNedge(pos[fx],k);
        ADDNedge(pos[u]+1,-k);
        u = fa[fx];
        fx = Top[u];
    }
    if(dep[u] > dep[v]) swap(u,v);
    ADDNedge(pos[u],k);
    ADDNedge(pos[v]+1,-k);
}

inline int in()
{
    char ch;
    int a = 0;
    while((ch = getchar()) == ' ' || ch == '
');
    a += ch - '0';
    while((ch = getchar()) != ' ' && ch != '
')
    {
        a *= 10;
        a += ch - '0';
    }
    return a;
}

inline void out(lll num){
    bool flag=false;
    if(num<0){
        putchar('-');
        num=-num;
    }
    int ans[22],top=0;
    while(num!=0){
        ans[top++]=num%10;
        num/=10;
    }
    if(top==0)
        putchar('0');
    for(int i=top-1;i>=0;i--){
        char ch=ans[i]+'0';
        putchar(ch);
    }
}

int main()
{
    int u,v,k,i,j,t,cs = 1;
    char ss[10];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(i=1;i<n;i++)
        {
            edge[i].u = in();
            edge[i].v = in();
            addedge(edge[i].u,edge[i].v);
        }
        dep[0] = 0;
        dfs(1,0);
        dfs2(1,1);
        while(m--)
        {
            scanf("%s",ss);
            u = in(), v = in(), k = in();
            if(ss[3] == '1')    //node
                AddNode(u,v,k);
            else
                AddEdge(u,v,k);
        }
        printf("Case #%d:
",cs++);
        lll ansedge = 0,ansnode = 0;
        for(i=1;i<=n;i++)
        {
            for(j=headn[i];j!=-1;j=Qn[j].next)
                ansnode += Qn[j].v;
            for(j=heade[i];j!=-1;j=Qe[j].next)
                ansedge += Qe[j].v;
            nans[apos[i]] = ansnode;
            eans[apos[i]] = ansedge;
        }
        for(i=1;i<=n;i++)
        {
            out(nans[i]);
            printf("%c",i==n?'
':' ');
        }
        for(i=1;i<n;i++)
        {
            int u = edge[i].u, v = edge[i].v;
            if(dep[u] > dep[v]) swap(u,v);
            out(eans[v]);
            printf("%c",i==n-1?'
':' ');
        }
        if(n == 1) puts("");    //PE..
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/whatbeg/p/4003880.html