hdu5044 Tree 上海网络赛1003 LCA+输入输出外挂

Tree

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


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

  之前也就做了一道类似LCA的题,对LCA还不是很熟悉,比赛的时候感觉是LCA但是不会写。

  看了题解,仔细想想这题其实真不难。。就是记录每个操作,最后从叶子到根网上遍历一遍,每次把要修改的值传上去就行了。。

  对点u,v加w就是:add1[u]+=w,add1[v]+=w,x=lca(u,v),add[x]-=w(因为传上来两个w),因为到了x之后不能再往上传,设sub[x]+=x,每个点的add值减去sub值就是要往上传的值。

  设add2[u]为u和fa[u]的边要增加的值,那么对边操作add2[u]+=w,add2[v]+=w,add2[x]-=2*w。

  因为这题要按输入的顺序输出边的权值,那么还要记录u和u的父节点之间的边的编号。

  注意要输入输出外挂才能过。。。。。。。

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<set>
#include<map>
#include<stack>
#define INF 0x3f3f3f3f
#define MAXN 100010
#define LOGMAXN 20
#define MAXM 1500
#define MOD 1000000007
#define MAXNODE 8*MAXN
#define eps 1e-10
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
int T,N,M,L[MAXN],anc[MAXN][LOGMAXN],fa[MAXN],e[MAXN],deg[MAXN];
LL add1[MAXN],add2[MAXN],sub[MAXN],node[MAXN],edge[MAXN];
char str[10];
struct Edge{
    int to,id;
    Edge(){}
    Edge(int to,int id):to(to),id(id){}
};
vector<Edge> G[MAXN];
void DFS(int u,int f,int level){
    L[u]=level;
    int len=G[u].size();
    for(int i=0;i<len;i++){
        int v=G[u][i].to;
        if(v!=f){
            deg[u]++;
            fa[v]=u;
            e[v]=G[u][i].id;
            DFS(v,u,level+1);
        }
    }
}
void lca_init(){
    for(int i=1;i<=N;i++){
        anc[i][0]=fa[i];
        for(int j=1;(1<<j)<=N;j++) anc[i][j]=-1;
    }
    for(int j=1;(1<<j)<=N;j++)
        for(int i=1;i<=N;i++) if(anc[i][j-1]!=-1){
            int a=anc[i][j-1];
            anc[i][j]=anc[a][j-1];
        }
}
int lca(int p,int q){
    if(L[p]<L[q]) swap(p,q);
    int log;
    for(log=0;(1<<log)<=L[p];log++);
    log--;
    for(int i=log;i>=0;i--) if(L[p]-(1<<i)>=L[q]) p=anc[p][i];
    if(p==q) return p;
    for(int i=log;i>=0;i--) if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
        p=anc[p][i];
        q=anc[q][i];
    }
    return fa[p];
}
void solve(){
    queue<int> q;
    for(int i=1;i<=N;i++) if(!deg[i]) q.push(i);    //叶子节点
    while(!q.empty()){
        int x=q.front();
        q.pop();
        node[x]=add1[x];
        add1[x]-=sub[x];
        edge[e[x]]=add2[x];
        int f=fa[x];
        add1[f]+=add1[x];
        add2[f]+=add2[x];
        if(!(--deg[f])) q.push(f);  //子节点都处理完了,成为叶子节点
    }
}
template <class T>
inline bool scan_d(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0; //EOF
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
inline void out(long long x) {
    if(x>9) out(x/10);
    putchar(x%10+'0');
}
int main(){
    freopen("in.txt","r",stdin);
    int cas=0;
    scan_d(T);
    while(T--){
        scan_d(N);
        scan_d(M);
        for(int i=1;i<=N;i++) G[i].clear();
        int u,v;
        for(int i=1;i<=N-1;i++){
            scan_d(u);
            scan_d(v);
            G[u].push_back(Edge(v,i));
            G[v].push_back(Edge(u,i));
        }
        memset(fa,0,sizeof(fa));
        memset(deg,0,sizeof(deg));
        DFS(1,-1,0);
        lca_init();
        memset(add1,0,sizeof(add1));
        memset(add2,0,sizeof(add2));
        memset(sub,0,sizeof(sub));
        while(M--){
            int u,v,w;
            scanf("%s",str);
            scan_d(u);
            scan_d(v);
            scan_d(w);
            int x=lca(u,v);
            if(str[3]=='1'){
                add1[u]+=w;
                add1[v]+=w;
                add1[x]-=w;
                sub[x]+=w;
            }
            else{
                add2[u]+=w;
                add2[v]+=w;
                add2[x]-=w*2;
            }
        }
        solve();
        printf("Case #%d:\n",++cas);
        for(int i=1;i<=N;i++){
            if(i>1) printf(" ");
            out(node[i]);
        }
        puts("");
        if(N==1) puts("");
        else{
            for(int i=1;i<=N-1;i++){
                if(i>1) printf(" ");
                out(edge[i]);
            }
            puts("");
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值