2014上海网络预选赛1003(树链剖分)HDU5044

本文详细介绍了一种基于树链剖分算法的经典问题解决方法,包括如何通过区间加操作更新节点和边的值,适用于处理大规模树状结构数据的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tree

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


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

题意:两种操作,将u和v路径之间点的权值+w,将u和v路径之间边的权值+w

思路:树链剖分裸题

            这题就是类似于在一段区间上+一个数,可以用经典的方法,只需在区间头+w,在区间尾-w即可

            先将树形转线性,然后对每条链进行上述操作就好了

            对于边操作有一点要注意,因为每个点只与它父亲的边绑定,所以要更新u和v之间的边的时候,u和v的祖先f所绑定的边是不能更新的

            因为那条边是不在u和v的路径上的

            这题时间卡的紧,输入挂是必须的

#pragma comment(linker,"/STACK:102400000,102400000")
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef __int64 ll;
const int MAXN = 100010;
int head[MAXN];
int next[MAXN<<1];
int edge[MAXN<<1];
int esz;
int deep[MAXN];
int son[MAXN];
int fa[MAXN];
int sz[MAXN];
int ord[MAXN];
int up[MAXN];
int ha[MAXN];
int bian[MAXN];
int id[MAXN<<1];
int dfs_clock;
int n;
ll ans1[MAXN];
ll ans2[MAXN];
ll ans3[MAXN];
ll ans4[MAXN];
inline int get(){
    int ret=0;
    char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)){
        ret=ret*10+(int)(c-'0');
        c=getchar();
    }
    return ret;
}
void init()
{
    memset(head,-1,sizeof(head));
    memset(ans1,0,sizeof(ans1));
    memset(ans2,0,sizeof(ans2));
    esz=0;dfs_clock=0;deep[0]=0;
}

void add(int u,int v,int i)
{
    edge[esz]=v;
    next[esz]=head[u];
    id[esz]=i;
    head[u]=esz++;
}

void dfs(int u,int p)
{
    fa[u]=p;
    deep[u]=deep[p]+1;
    sz[u]=1;
    son[u]=0;
    for(int i=head[u];i!=-1;i=next[i]){
        int v=edge[i];
        if(v==p)continue;
        dfs(v,u);
        bian[v]=id[i];
        sz[u]+=sz[v];
        if(!son[u] || sz[v] > sz[son[u]]){
            son[u]=v;
        }
    }
}

void dfs1(int u,int p)
{
    ord[u]=++dfs_clock;
    up[u]=p;
    ha[ord[u]]=u;
    if(!son[u])return;
    dfs1(son[u],p);
    for(int i=head[u];i!=-1;i=next[i]){
        int v=edge[i];
        if(v==fa[u] || v==son[u])continue;
        dfs1(v,v);
    }
}

void fx(int u,int v,int z)
{
    int pu=up[u];
    int pv=up[v];
    while(pu != pv){
        if(deep[pu]deep[v])swap(u,v);
    ans1[ord[u]]+=z;
    ans1[ord[v]+1]-=z;
}

void fx2(int u,int v,int z)
{
    int pu=up[u];
    int pv=up[v];
    while(pu != pv){
        if(deep[pu]deep[v])swap(u,v);
    ans2[ord[son[u]]]+=z;
    ans2[ord[v]+1]-=z;
}

int main()
{
    int m;
    int t,tt=0;
    scanf("%d",&t);
    while(t--)
    {
        n=get();m=get();
        init();
        for(int i=1;i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值