HDU-5044 Tree 树链剖分

树链剖分基础题,将树剖分后把操作化为在x处+z和在y+1处-z处理,注意处理边的时候相当于将(A,B)边上的信息压到点B上。

Tree

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3221 Accepted Submission(s): 567

Problem Description
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N

There are N - 1 edges numbered from 1 to N - 1.

Each node has a value and each edge has a value. The initial value is 0.

There are two kind of operation as follows:

● 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.

After finished M operation on the tree, please output the value of each node and edge.

Input
The first line of the input is T (1 ≤ T ≤ 20), which stands for the number of test cases you need to solve.

The first line of each case contains two integers N ,M (1 ≤ N, M ≤105),denoting the number of nodes and operations, respectively.

The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.

For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -105 ≤ k ≤ 105)

Output
For each test case, print a line “Case #t:”(without quotes, t means the index of the test case) at the beginning.

The second line contains N integer which means the value of each node.

The third line contains N - 1 integer which means the value of each edge according to the input order.

Sample Input
2
4 2
1 2
2 3
2 4
ADD1 1 4 1
ADD2 3 4 2
4 2
1 2
2 3
1 4
ADD1 1 4 5
ADD2 3 2 4

Sample Output
Case #1:
1 1 0 1
0 2 2
Case #2:
5 0 0 5
0 4 0

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#define maxn 200009
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define maxm 800009
using namespace std;
struct ss{
    int x,y;
    int next;
}line[maxm];
int N,M;
int tot=0;
int fa[maxn],deep[maxn];
int head[maxn],siz[maxn],top[maxn];
int Newid[maxn],son[maxn],cnt=0;
int oldid[maxn],ans[maxn];
int c1[maxn],c2[maxn];
void Findheavyedge(int x,int father,int depth)
{
    int child,Max=0;
    fa[x]=father;deep[x]=depth;siz[x]=1;son[x]=0;
    for(int k=head[x];k;k=line[k].next)
    {
        child=line[k].y;
        if(child!=father)
        {
            Findheavyedge(child,x,depth+1);
            siz[x]+=siz[child];
            if(siz[child]>Max)
            {
                Max=siz[child];
                son[x]=child;
            }
        }
    }
}
void connect(int x,int ancestor)
{
    Newid[x]=++cnt;oldid[Newid[x]]=x;top[x]=ancestor;
    if(son[x]!=0)connect(son[x],ancestor);
    int child;
    for(int k=head[x];k;k=line[k].next)
    {
        child=line[k].y;
        if(child==fa[x]||child==son[x])continue;
        connect(child,child);
    }
}
void insert(int x,int y)
{
    tot++;
    line[tot].x=x;
    line[tot].y=y;
    line[tot].next=head[x];
    head[x]=tot;
}
void ADD1(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        c1[Newid[top[x]]]+=z;
        c1[Newid[x]+1]-=z;
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    c1[Newid[x]]+=z;
    c1[Newid[y]+1]-=z;
}
void ADD2(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        c2[Newid[top[x]]]+=z;
        c2[Newid[x]+1]-=z;
        x=fa[top[x]];
    }
    if(x==y)return ;
    if(deep[x]>deep[y])swap(x,y);
    c2[Newid[x]+1]+=z;
    c2[Newid[y]+1]-=z;
}
void in(int &x)
{
    char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    for(x=ch-'0',ch=getchar();ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
int main()
{
    int T;
    int CASE=0;
    cin>>T;
    while(T--)
    {
        CASE++;
        cin>>N>>M;
        //重置
        memset(head,0,sizeof(head));
        cnt=0;tot=0;
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        int i,j,x,y,z;
        int u,v,k;
        for(i=1;i<N;i++)
        {
            scanf("%d%d",&x,&y);
            insert(x,y);
            insert(y,x);
        }
        Findheavyedge(1,0,1);
        connect(1,1);
        char str[10];
        for(i=1;i<=M;i++)
        {
            scanf("%s",str);
            scanf("%d%d%d",&u,&v,&k);
            if(str[3]=='1')
            {
                ADD1(u,v,k);
            }
            if(str[3]=='2')
            {
                ADD2(u,v,k);
            }
        }
        printf("Case #%d:\n",CASE);
        for (int i=1;i<=N;i++) c1[i]=c1[i-1]+c1[i],c2[i]=c2[i-1]+c2[i];
        for (int i=1;i<=N;i++)
        {
            if (i>1) printf(" ");
            printf("%d",c1[Newid[i]]);
        }
        printf("\n");
        int cnt=0;
        for (int i=1;i<=tot;i+=2)
        {
            if (i>1) printf(" ");
            int x=line[i].x,y=line[i].y;
            if (deep[x]<deep[y]) swap(x,y);
            printf("%d",c2[Newid[x]]);
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值