HDU5044--Tree(树链剖分)

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 ≤10 5),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, -10 5 ≤ k ≤ 10 5)
 

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
 
思路:树链剖分。。常规做法要TLE、、、
这里先把链拆成线段,然后线扫描一遍、
                                     #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <cassert>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define travel(e, u) for(int e = u, v = vv[u]; e; e = nxt[e], v = vv[e])
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{

//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);


    work();
}

void scanf(int & x, char c = 0)
{
    while((c = getchar()) < '0' || c > '9');

    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9') x = x * 10 + (c - '0');
}

/*****************************************华丽分割线**********************************************/

#define maxn 200800
#define N 100080
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
int first[N],nxt[maxn],vv[maxn];
int fa[N],Pos[N],Size[N],Son[N],fPos[N];
int dep[N],Top[N];
char ope[10];
LL Ans1[N],Ans2[N];
int e,pos;
int firstadd[N],Nxt[10*maxn],Vv[10*maxn];
int firstadd2[N],Nxt2[10*maxn],Vv2[10*maxn];
int E,E2;

void scanf_f(int & a)  
{  
    bool ok = 0;
    a = 0;  
    char c;  
    while((c = getchar()) < '0' || c > '9')
    {
        if(c == '-')    ok = 1;
    }

    a = c - '0';  
    while((c = getchar()) >= '0' && c <= '9')  
        a = a*10 + c - '0';  
    if(ok)    a = -a;
}  
void init(int n)
{
    e = pos = E = E2 = 0;
    memset(first,-1,sizeof(first));
    memset(firstadd,-1,sizeof(firstadd));
    memset(firstadd2,-1,sizeof(firstadd2));
    memset(Son,-1,sizeof(Son));
}
void addedge(int u,int v)
{
    vv[e] = v;  nxt[e] = first[u];  first[u] = e++;
    vv[e] = u;  nxt[e] = first[v];  first[v] = e++;
}

void AddEdge(int u,int v)
{
    Vv[E] = v;    Nxt[E] = firstadd[u];    firstadd[u] = E++;
}
void AddEdge2(int u,int v)
{
    Vv2[E2] = v;    Nxt2[E2] = firstadd2[u];    firstadd2[u] = E2++;
}
void dfs(int u,int pre)
{
    dep[u] = dep[pre] + 1;
    Size[u] = 1;
    for(int i = first[u];i != -1;i = nxt[i])
    {
        int v = vv[i];
        if(v == pre)    continue;
        fa[v] = u;
        dfs(v,u);
        Size[u] += Size[v];
        if(Son[u] == -1 || Size[v] > Size[Son[u]])
            Son[u] = v;
    }
}

void dfs2(int u,int t)
{
    Pos[u] = ++pos;
    fPos[pos] = u;
    Top[u] = t;
    if(Son[u] != -1)
        dfs2(Son[u],t);
    for(int i = first[u];i != -1;i = nxt[i])
    {
        int v = vv[i];
        if(v != fa[u] && v != Son[u])
            dfs2(v,v);
    }
}

void gao(int u,int v,int add)
{
    int f1 = Top[u],f2 = Top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(u,v);
            swap(f1,f2);
        }
        AddEdge(Pos[f1],add);
        AddEdge(Pos[u]+1,-add);
        u = fa[f1]; f1 = Top[u];
    }
    if(dep[u] > dep[v]) swap(u,v);
    AddEdge(Pos[u],add);
    AddEdge(Pos[v]+1,-add);
}
void gao1(int u,int v,int add)
{
    int f1 = Top[u],f2 = Top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(u,v);
            swap(f1,f2);
        }
        if(f1 == u)
        {
            AddEdge2(Pos[f1],add);
            AddEdge2(Pos[u]+1,-add);
        }
        else
        {
            AddEdge2(Pos[f1],add);
            AddEdge2(Pos[u]+1,-add);
        }
        u = fa[f1]; f1 = Top[u];
    }
    if(dep[u] > dep[v]) swap(u,v);
    AddEdge2(Pos[Son[u]],add);
    AddEdge2(Pos[v]+1,-add);
}
struct Edge
{
    int u,v;
}edge[N];
void work()
{
    int t,cas = 0;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf_f(n);
        scanf_f(m);
        init(n);
        for(int i = 1;i < n;i++)
        {
            int u,v;
            scanf_f(u);
            scanf_f(v);
            addedge(u,v);
            edge[i].u = u,edge[i].v = v;
        }
        dep[1] = 0;
        dfs(1,1);
        dfs2(1,1);
        int u,v,k;
        for(int i = 1;i <= m;i++)
        {
            scanf("%s",ope);
            if(ope[3] == '1')
            {
                
                scanf_f(u);
                scanf_f(v);
                scanf_f(k);
                gao(u,v,k);
            }
            else
            {
                
                scanf_f(u);
                scanf_f(v);
                scanf_f(k);
                gao1(u,v,k);
            }
        }
        printf("Case #%d:\n",++cas);
        LL ans1 = 0,ans2 = 0;
        for(int i = 1;i <= n;i++)
        {
            for(int j = firstadd[i];j != -1;j = Nxt[j])
                ans1 += Vv[j];
            for(int j = firstadd2[i];j != -1;j = Nxt2[j])
                ans2 += Vv2[j];
            Ans1[fPos[i]] = ans1;
            Ans2[fPos[i]] = ans2;
        }
        for(int i = 1;i <= n;i++)
        {
            printf("%I64d",Ans1[i]);
            if(i == n)    puts("");
            else printf(" ");
        }
        for(int i= 1;i < n;i++)
        {
            u = edge[i].u,v = edge[i].v;
            if(dep[u] > dep[v])    swap(u,v);
            printf("%I64d",Ans2[v]);
            if(i != n-1)    
            printf(" ");
        }
        puts("");
    }
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值