[luogu P3806] 【模板】点分治1

[luogu P3806] 【模板】点分治1

题目背景

感谢hzwer的点分治互测。

题目描述

给定一棵有n个点的树

询问树上距离为k的点对是否存在。

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制
2 1
1 2 2
2
输出样例#1: 复制
AYE

说明

对于30%的数据n<=100

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

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

首先这是点分裸题啊。。刷过点分的dalao都知道。

但似乎这题我只会calc里面n^2暴力扫?用不来m的100?

没事,让我们证明一下复杂度。。

T(n)=2T(n/2)+n^2。

然后我并不会主定理。。画了下二叉树图。

然后发现T(n)=2n^2(n^2+(1/2)n^2+(1/4)n^2+...)。

然后,因为n=10000,把常数写小一点,有点信仰就可以了。

code:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define ms(a,x) memset(a,x,sizeof a)
 5 using namespace std;
 6 const int N=10005,D=10000005;
 7 int n,tot,lnk[N],nxt[N<<1],son[N<<1],w[N<<1];
 8 int ro,subn,cnt,siz[N],mxs[N],dep[N],d[N];
 9 int m,c[D]; bool vis[N];
10 void add (int x,int y,int z) {
11     nxt[++tot]=lnk[x],lnk[x]=tot;
12     son[tot]=y,w[tot]=z;
13 }
14 void dfs_size(int x,int p) {
15     siz[x]=1,mxs[x]=0;
16     for (int j=lnk[x]; j; j=nxt[j]) {
17         if (son[j]==p||vis[son[j]]) continue;
18         dfs_size(son[j],x);
19         siz[x]+=siz[son[j]];
20         if (mxs[x]<siz[son[j]]) mxs[x]=siz[son[j]];
21     }
22     if (mxs[x]<subn-mxs[x]) mxs[x]=subn-mxs[x];
23     if (mxs[x]<mxs[ro]) ro=x;
24 }
25 void dfs_depth (int x,int p) {
26     dep[++cnt]=d[x];
27     for (int j=lnk[x]; j; j=nxt[j]) {
28         if (son[j]==p||vis[son[j]]) continue;
29         d[son[j]]=d[x]+w[j];
30         dfs_depth(son[j],x);
31     }
32 }
33 void calc (int x,int v) {
34     cnt=0,dfs_depth(x,0);
35     for (int i=1; i<cnt; ++i) {
36         for (int j=i+1; j<=cnt; ++j) {
37             c[dep[i]+dep[j]]+=v;
38         }
39     }
40 }
41 void node_divide (int x) {
42     ro=0,dfs_size(x,0),vis[ro]=1;
43     d[ro]=0,calc(ro,1);
44     for (int j=lnk[ro]; j; j=nxt[j]) {
45         if (vis[son[j]]) continue;
46         calc(son[j],-1);
47         subn=siz[son[j]];
48         node_divide(son[j]);
49     }
50 }
51 int main() {
52     int x,y,z;
53     scanf("%d%d",&n,&m);
54     for (int i=1; i<n; ++i) {
55         scanf("%d%d%d",&x,&y,&z);
56         add(x,y,z),add(y,x,z);
57     }
58     ro=0,mxs[0]=n,subn=n;
59     node_divide(1);
60     for (int i=1; i<=m; ++i) {
61         scanf("%d",&x);
62         printf("%s\n",c[x]>0?"AYE":"NAY");
63     }
64     return 0;
65 }
View Code
posted @ 2017-12-09 16:28 PinkExSu0v0 阅读(...) 评论(...) 编辑 收藏