BOJ 292 MABODX

MABODX

 

Accept:17   Submit:88
Time Limit:4000MS   Memory Limit:65536KB

Description

There is a country which has N city. Because The king spend littlemoney on the road ,so there is one and only one path from any cityto another city,every city has a apple tree.The apple in one citywhich has only one apple tree is the same.

Now The king wants to ask Bobo some questions .The king wants toknow if he walk from A city to B city and pick apples from the appletree when he pass one city (including A city and B city) what is thesum value of apples.But Bobo can't the question so he turns to yourhelp.


Input

There are many cases.

The first line of every case is N andM.N(1<=N<=50000) means N city, M(1<=M<=50000) means Mquestion .

Then N-1 line represent the roadbetween the country. Then the N line has N number the ith number onthe N line means the value of the apple in the ith city(the value isless than 10000) .

Then M line .Each line has 2 numberA(1<=A<=N) and B(1<=B<=N) ,means king ask if he walk fromcity A to city B.


Output

The sum value of appple of everyquestion. Output one line one answer.


Sample Input

3 2

1 2

1 3

5 7 10

1 3

3 2


Sample Output

15

22


Source

mabodx

此题用LCA做,首先预处理dfs求出每一点到根节点的权值,再LCA即可

#include<cstdio>
#include<string.h>
using namespace std;
int n,m,num[50100],sum[50100],ans[50100];
int head1[50100],head2[50100],cnt,f[50100],ff[50100];
bool flag[50100];
struct Edge{
    int f,v,id,next;
}edge[50100*7];
void addedge(int u,int v,int id,int *head){
    edge[cnt].f=u;
    edge[cnt].v=v;
    edge[cnt].id=id;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].f=v;
    edge[cnt].v=u;
    edge[cnt].id=id;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
void dfs(int u,int father){
	int i;
	for(i=head1[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v!=father){
			sum[v]=sum[u]+num[v];
            dfs(v,u);
        }
    }
}
int find(int u){
	int s;
	for(s=u;f[s]!=s;s=f[s]);
	while(s!=u){
		int tmp=f[u];
		f[u]=s;
		u=tmp;
	}
	return s;
}
void tarjan(int u,int father){
    int i;
    f[u]=u;
    for(i=head1[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v!=father){
            tarjan(v,u);
            f[v]=u;
        }
    }
    flag[u]=1;
    for(i=head2[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(flag[v]){
			int t=find(v);
			ans[edge[i].id]=sum[edge[i].f]+sum[edge[i].v]-2*sum[t]+num[t];
        }
    }
}
int main(){
    int i,j;
    while(scanf("%d %d",&n,&m)==2){
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        memset(flag,0,sizeof(flag));
		memset(ff,0,sizeof(ff));
        memset(sum,0,sizeof(sum));
        memset(f,0,sizeof(f));
        cnt=0;
        for(i=1;i<n;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v,0,head1);
        }
        for(i=1;i<=n;i++)
            scanf("%d",&num[i]);
        for(i=1;i<=m;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v,i,head2);
        }
		sum[1]=num[1];
		dfs(1,0);
        tarjan(1,0);
        for(i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
}



打比赛时我一直用的带权值的并查集做,一直WA,现在也没查出错,望路过的大牛能够指正

#include<cstdio>
#include<string.h>
using namespace std;
int n,m,num[50100],sum[50100],ans[50100];
int head1[50100],head2[50100],head3[50100],cnt,f[50100],ff[50100];
bool vis[50100],flag[50100];
struct Edge{
    int f,v,id,next;
}edge[50100*7];
void addedge(int u,int v,int id,int *head){
    edge[cnt].f=u;
    edge[cnt].v=v;
    edge[cnt].id=id;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].f=v;
    edge[cnt].v=u;
    edge[cnt].id=id;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int find(int u){
    if(f[u]==u){
        sum[u]=num[u];
        return u;
    }
    f[u]=find(f[u]);
    sum[u]=sum[ff[u]]+num[u];
    return f[u];
}
void tarjan(int u){
    int i;
    f[u]=u;
    for(i=head1[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(!vis[v] ){
            vis[v]=1;
            tarjan(v);
            f[v]=u;
	    ff[v]=u;
	    find(v);
        }
    }
    flag[u]=1;
    for(i=head2[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(flag[v]){
			int t=find(v);
            edge[cnt].v=i;
            edge[cnt].next=head3[t];
            head3[t]=cnt++;
        }
    }
    for(i=head3[u];i!=-1;i=edge[i].next){
        int j=edge[i].v;
        int uu=edge[j].f;
        int vv=edge[j].v;
        int id=edge[j].id;
        find(uu);
        ans[id]=sum[uu]+sum[vv]-num[u];
    }
}
int main(){
    int i,j;
    while(scanf("%d %d",&n,&m)==2){
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        memset(head3,-1,sizeof(head3));
        memset(vis,0,sizeof(vis));
        memset(flag,0,sizeof(flag));
	memset(ff,0,sizeof(ff));
        memset(sum,0,sizeof(sum));
        memset(f,0,sizeof(f));
        cnt=0;
        for(i=1;i<n;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v,0,head1);
        }
        for(i=1;i<=n;i++)
            scanf("%d",&num[i]);
        for(i=1;i<=m;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v,i,head2);
        }
        vis[1]=1;
        tarjan(1);
        for(i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
}


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值