ACdream 1028 - Path (树形DP)

Path

Time Limit: 4000/2000MS (Java/Others)  Memory Limit: 128000/64000KB (Java/Others)
Problem Description

Check if there exists a path of length  l  in the given tree with weight assigned to each edges.

Input

The first line contains two integers  n  and  q , which denote the number of nodes and queries, repectively.

The following  (n1)  with three integers  ai,bi,ci , which denote the edge between  ai  and  bi , with weight  ci .

Note that the nodes are labled by  1,2,,n .

The last line contains  q  integers  l1,l2,,lq , denote the queries.

(1n,q105,1ci2)

Output

For each query, print the result in seperated line. If there exists path of given length, print "Yes". Otherwise, print "No".

Sample Input
4 6
1 2 2
2 3 1
3 4 2
0 1 2 3 4 5
Sample Output
Yes
Yes
Yes
Yes
No
Yes
Source
ftiasch


题意:

给你一个生成树,权值不是1就是2。 给你q个询问,每次问你能不能找到一条路是给你的这个权值。


POINT:

因为权值不是1就是2,我们只要找出路中最大的偶数和最大的奇数。

如果询问的偶数比最大的偶数大,就是no。

询问的奇数比最大的奇数大,就是no。


因为一条路的权值为sum,那么两边的头,要么有2---只要去掉这个2,就可以得到sum-2。

要么没有2(即2个1),---去掉这两个1,就可以得到sum-2。


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 2e5+555;

int dp[maxn][2];
int head[maxn],nxt[maxn],w[maxn],to[maxn];
int vis[maxn];
int JI,OU;
int sz=0;

void add(int u,int v,int c)
{
	nxt[sz]=head[u];
	dp[sz][0]=dp[sz][1]=0;
	to[sz]=v;
	w[sz]=c;
	head[u]=sz++;
}
void dfs(int now,int pre)
{
	for(int i=head[now];~i;i=nxt[i]){
		if(vis[i]) continue;
		int v=to[i];
		int c=w[i];
		//if(v==pre) continue;
		vis[i]=1;
		dfs(v,now);

		int ji=0,ou=0;
		for(int j=head[v];~j;j=nxt[j]){
			if(to[j]==now) continue;
			ji=max(ji,dp[j][1]);
			ou=max(ou,dp[j][0]);
		}
		if(c==1){
			dp[i][1]=ou+1;
			if(ji!=0)
				dp[i][0]=ji+1;
		}else{
			if(ji!=0)
				dp[i][1]=ji+2;
			dp[i][0]=ou+2;
		}
		OU=max(OU,dp[i][0]);
		JI=max(JI,dp[i][1]);
	}
}
int main()
{
	int n,m;
	while(~scanf("%d %d",&n,&m)){
		for(int i=1;i<=n;i++) head[i]=-1;
		JI=OU=sz=0;
		memset(vis,0,sizeof vis);
		for(int i=2;i<=n;i++){
			int u,v,w;
			scanf("%d %d %d",&u,&v,&w);
			add(u,v,w);
			add(v,u,w);
		}
		dfs(1,0);
		for(int i=1;i<=m;i++){
			int ll;
			scanf("%d",&ll);
			if(ll<0) printf("No\n");
			else{
				if(ll&1){
					if(ll<=JI){
						printf("Yes\n");
					}else{
						printf("No\n");
					}
				}else{
					if(ll<=OU){
						printf("Yes\n");
					}else{
						printf("No\n");
					}
				}
			}
		}

	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值