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 == '\n');

    a += ch - '0';

    while((ch = getchar()) != ' ' && ch != '\n')

    {

        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:\n",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?'\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?'\n':' ');

        }

        if(n == 1) puts("");    //PE..

    }

    return 0;

}
View Code

 

你可能感兴趣的:(tree)