[洛谷3806] 點分治1
阿新 • • 發佈:2018-07-29
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; 8struct 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