点分治练习: boatherds

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点分治练习: boatherds相关的知识,希望对你有一定的参考价值。

 

【题面】

求一颗树上距离为K的点对是否存在

输入数据

n,m

接下来n-1条边a,b,c描述a到b有一条长度为c的路径

接下来m行每行询问一个K

输出数据

对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)

数据范围

对于30%的数据n<=100

对于60%的数据n<=1000,m<=50

对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000

 

【思路】

       树分治。

       离线存储m个询问。分治判断该m个询问是否能够出现。

       具体操作:假设当前处理第S个子树,exist[]中存储着前S-1棵子树中出现过的dis,一遍dfs得到S子树的所有dis,并判断m个询问。

       时间复杂度为O(nmlogn)

       别放了exist[0] <- 0和清空exist就好了QAQ

 

【代码】

 

 1 #include<cstdio>
 2 #include<vector>
 3 #include<queue>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 8 using namespace std;
 9 
10 const int N = 1e4+10;
11 const int M = 1e7+10;
12 
13 struct Edge {
14     int v,w;
15     Edge(int v=0,int w=0) :v(v),w(w){}
16 };
17 vector<Edge> g[N];
18 int n,m,k,q[N],ans[N];
19 int root,size,siz[N],f[N],dis[N],vis[N],tmp[N],l1,l2,exist[M];
20 
21 void getroot(int u,int fa) {
22     siz[u]=1; f[u]=0; exist[0]=1;
23     for(int i=0;i<g[u].size();i++) {
24         int v=g[u][i].v;
25         if(v!=fa && !vis[v]) {
26             getroot(v,u);
27             siz[u]+=siz[v];
28             if(siz[v]>f[u]) f[u]=siz[v];
29         }
30     }
31     f[u]=max(f[u],size-siz[u]);
32     if(f[u]<f[root]) root=u;
33 }
34 void dfs(int u,int fa) {
35     tmp[++l1]=dis[u];
36     for(int i=0;i<g[u].size();i++) {
37         int v=g[u][i].v;
38         if(v!=fa && !vis[v]) {
39             dis[v]=dis[u]+g[u][i].w;
40             dfs(v,u);
41         }
42     }
43 }
44 void solve(int u) {
45     vis[u]=1;
46     l1=l2=0;
47     for(int i=0;i<g[u].size();i++) {
48         int v=g[u][i].v;
49         l2=l1+1;
50         if(!vis[v]) {
51             dis[v]=g[u][i].w;
52             dfs(v,u);
53             FOR(i,l2,l1) FOR(j,1,m) 
54                 if(q[j]>=tmp[i] && exist[q[j]-tmp[i]]) ans[j]=1;
55             FOR(i,l2,l1) exist[tmp[i]]=1;
56         }
57     }
58     FOR(i,1,l1) exist[tmp[i]]=0;
59     for(int i=0;i<g[u].size();i++) {
60         int v=g[u][i].v;
61         if(!vis[v]) {
62             root=0; getroot(u,-1);
63             size=siz[v]; solve(root);
64         }
65     }
66 }
67 
68 void read(int& x) {
69     char c=getchar(); int f=1; x=0;
70     while(!isdigit(c)){if(c==-) c=-1; c=getchar();}
71     while(isdigit(c)) x=x*10+c-0,c=getchar();
72     x*=f;
73 }
74 int main() {
75     //freopen("in.in","r",stdin);
76     //freopen("out.out","w",stdout);
77     read(n),read(m);
78     int u,v,w;
79     FOR(i,1,n-1) {
80         read(u),read(v),read(w);
81         g[u].push_back(Edge(v,w));
82         g[v].push_back(Edge(u,w));
83     }
84     FOR(i,1,m) read(q[i]);
85     size=n; f[0]=1e9; root=0;
86     getroot(1,-1); solve(root);
87     FOR(i,1,m) if(ans[i]) puts("AYE"); else puts("NAY");
88     return 0;
89 }

 

以上是关于点分治练习: boatherds的主要内容,如果未能解决你的问题,请参考以下文章

poj2114 Boatherds

BZOJ1468 点分治入门练习题

点分治练习:不虚就是要AK

牛客练习赛81 D.小 Q 与树(点分治+容斥)

牛客练习赛84:牛客推荐系统开发之标签重复度(点分治+动态开点权值线段树)

牛客练习赛105 D.点分治分点(spfa&bfs)