1. 程式人生 > >[洛谷3806] 點分治1

[洛谷3806] 點分治1

style r++ 但是 urn point algorithm += namespace 格式

題目背景

感謝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

跟BZOJ1316是一樣的,但是辣雞bzoj他卡我常。。

這道題有兩種思路,一種是把所有的路徑長度全用點分治刷出來O(1)回答詢問,但好像我怎麽想都是O(n^2)的,還不如直接枚舉兩點求LCA,另一種則是對每個詢問求,時間復雜度是O(q*n*logn),然而n和q都比較小,就跑過去了。

代碼:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define M 10010
  6 #define inf 1e8
  7 using namespace std;
  8
struct point{ 9 int next,to,dis; 10 }e[M<<1]; 11 int n,m,num,S,maxn,root,K,ans,q; 12 int head[M],dis[M],maxsize[M],size[M]; 13 bool vis[M]; 14 void add(int from,int to,int dis) 15 { 16 e[++num].next=head[from]; 17 e[num].to=to; 18 e[num].dis=dis; 19 head[from]=num;
20 } 21 void getroot(int x,int fa) 22 { 23 size[x]=1; maxsize[x]=0; 24 for(int i=head[x];i;i=e[i].next) 25 { 26 int to=e[i].to; 27 if(vis[to]||to==fa) continue; 28 getroot(to,x); 29 maxsize[x]=max(maxsize[x],size[to]); 30 size[x]+=size[to]; 31 } 32 maxsize[x]=max(maxsize[x],S-size[x]); 33 if(maxsize[x]<maxn) maxn=maxsize[x],root=x; 34 } 35 void getdis(int x,int fa,int len) 36 { 37 dis[++num]=len; 38 for(int i=head[x];i;i=e[i].next) 39 { 40 int to=e[i].to; 41 if(vis[to]||to==fa) continue; 42 getdis(to,x,len+e[i].dis); 43 } 44 } 45 int cal(int x,int len) 46 { 47 num=0; 48 getdis(x,0,len); 49 sort(dis+1,dis+1+num); 50 int l=1,r=num,suml=0,sumr=0,tot=0; 51 while(l<r) 52 { 53 if(dis[l]+dis[r]<K) l++; 54 else 55 { 56 if(dis[l]+dis[r]==K) 57 { 58 suml=1,sumr=1; 59 while(dis[l+1]==dis[l]&&l+1<r) l++,suml++; 60 while(dis[r-1]==dis[r]&&r-1>l) r--,sumr++; 61 tot+=suml*sumr; 62 l++; 63 } 64 r--; 65 } 66 } 67 return tot; 68 } 69 void solve(int x) 70 { 71 ans+=cal(x,0); 72 vis[x]=true; 73 for(int i=head[x];i;i=e[i].next) 74 { 75 int to=e[i].to; 76 if(vis[to]) continue; 77 ans-=cal(to,e[i].dis); 78 S=size[to]; root=0; maxn=inf; 79 getroot(to,0); solve(root); 80 } 81 } 82 int main() 83 { 84 scanf("%d%d",&n,&q); 85 for(int i=1;i<n;i++) 86 { 87 int x,y,z; scanf("%d%d%d",&x,&y,&z); 88 add(x,y,z); add(y,x,z); 89 } 90 for(int i=1;i<=q;i++) 91 { 92 scanf("%d",&K); 93 S=n; maxn=inf; getroot(1,0); ans=0; 94 memset(vis,false,sizeof(vis)); 95 solve(root); 96 if(ans) printf("AYE\n"); 97 else printf("NAY\n"); 98 } 99 return 0; 100 }

[洛谷3806] 點分治1