[BZOJ1316]树上的询问 点分治

1316: 树上的询问

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1017  Solved: 287
[Submit][Status][Discuss]

Description

一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No.

Input

第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径.

Output

输出有p行,Yes或No.

Sample Input

6 4
1 2 5
1 3 7
1 4 1
3 5 2
3 6 3
1
8
13
14

Sample Output

Yes
Yes
No
Yes


HINT

30%的数据,n≤100. 
100%的数据,n≤10000,p≤100,长度≤1000000. 

做完此题可看下POJ 3237 Tree

Source

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define maxn 100000
 8 using namespace std;
 9 int n,q;
10 int ask[maxn];
11 int ans[maxn];
12 struct edge {
13     int to,next,c;
14 }e[maxn*2];
15 int head[maxn],cnt;
16 void add(int u,int v,int c){e[cnt].to=v;e[cnt].next=head[u];e[cnt].c=c;head[u]=cnt++;}
17 int root;
18 int vis[maxn],size[maxn],sum,f[maxn];
19 void findrt(int x,int fa) {
20     size[x]=1;f[x]=0;
21     for(int i=head[x];i>=0;i=e[i].next) {
22         int to=e[i].to;if(to==fa||vis[to]) continue;
23         findrt(to,x);
24         size[x]+=size[to];
25         f[x]=max(f[x],size[to]);
26     }
27     f[x]=max(f[x],sum-size[x]);
28     if(f[x]<f[root]) root=x;
29 }
30 int dis[maxn],t[maxn],tt,tmp,num[maxn];
31 int dfs(int x,int fa,int d) {
32     dis[++tt]=d;
33     for(int i=head[x];i>=0;i=e[i].next) {
34         int to=e[i].to;if(to==fa||vis[to]) continue;
35         dfs(to,x,d+e[i].c);
36     }
37 }
38 void cal(int x,int fl,int d) {
39     tt=0;tmp=0;
40     dfs(x,0,d);
41     sort(dis+1,dis+tt+1);
42     for(int i=1;i<=tt;i++) {
43         if(dis[i]!=dis[i-1]||i==1) dis[++tmp]=dis[i],num[tmp]=1;
44         else num[tmp]++;
45     }
46     for(int i=1;i<=q;i++) {
47         for(int j=1;j<=tmp;j++)
48             if(num[j]>=2&&dis[j]*2==ask[i]) ans[i]+=fl*num[j]*(num[j]-1);
49         int l=1,r=tmp;
50         while(l<r) {
51             if(dis[l]+dis[r]>ask[i]&&l<r) r--;
52             else {
53                 if(dis[l]+dis[r]==ask[i]) ans[i]+=fl*num[l]*num[r];
54                 l++;
55             }
56         }
57     }
58     
59 }
60 void work(int x) {
61     vis[x]=1;cal(x,1,0);
62     for(int i=head[x];i>=0;i=e[i].next) {
63         int to=e[i].to;if(vis[to]) continue;
64         cal(to,-1,e[i].c);
65         root=0;sum=size[to];findrt(to,x);
66         work(root);
67     }
68 }
69 int main() {
70     memset(head,-1,sizeof(head));
71     scanf("%d%d",&n,&q);
72     for(int i=1;i<n;i++) {
73         int a,b,c;
74         scanf("%d%d%d",&a,&b,&c);
75         add(a,b,c);add(b,a,c);
76     }
77     for(int i=1;i<=q;i++) scanf("%d",&ask[i]);
78     f[0]=2147483647;sum=n;
79     findrt(1,0);
80     work(root);
81     for(int i=1;i<=q;i++)
82         if(ans[i]>0||!ask[i]) printf("Yes\n");
83         else printf("No\n");
84 }
View Code

 

posted @ 2018-02-27 19:12  wls001  阅读(161)  评论(0编辑  收藏  举报