BZOJ_1316_樹上的詢問_點分治
阿新 • • 發佈:2018-04-14
tde tro fine string.h light RR ask () 個數
1 2 5
1 3 7
1 4 1
3 5 2
3 6 3
1
8
13
14
Yes
No
Yes
BZOJ_1316_樹上的詢問_點分治
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 41 2 5
1 3 7
1 4 1
3 5 2
3 6 3
1
8
13
14
Sample Output
YesYes
No
Yes
HINT
30%的數據,n≤100.
100%的數據,n≤10000,p≤100,長度≤1000000.
做完此題可看下POJ 3237 Tree
和Race那道題差不多,由於p很小可以暴力統計。
時間復雜度O(p*n*logn)
代碼:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 10050 #define maxl 1000000 int head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt,n,m; int fag[N],siz[N],ask[150],tot,solved[150],a[N],b[N],dis[N],root; bool used[N],buc[1000010][2]; inline void add(int u,int v,int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } void getroot(int x,int y) { fag[x]=0; siz[x]=1; int i; for(i=head[x];i;i=nxt[i]) { if(to[i]!=y&&!used[to[i]]) { getroot(to[i],x); siz[x]+=siz[to[i]]; fag[x]=max(fag[x],siz[to[i]]); } } fag[x]=max(fag[x],tot-siz[x]); if(fag[root]>fag[x]) {root=x;} } void getdep(int x,int y) { int i; if(dis[x]<=maxl){ a[++a[0]]=dis[x]; b[++b[0]]=dis[x]; } siz[x]=1; for(i=head[x];i;i=nxt[i]) { if(to[i]!=y&&!used[to[i]]) { dis[to[i]]=dis[x]+val[i]; getdep(to[i],x); siz[x]+=siz[to[i]]; } } } void getsiz(int x,int y) { int i; siz[x]=1; for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) { getsiz(to[i],x); siz[x]+=siz[to[i]]; } } void work(int x) { used[x]=1; int i,j,k; dis[x]=0; b[0]=0; b[++b[0]]=0; for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) { a[0]=0; a[++a[0]]=0; dis[to[i]]=val[i]; getdep(to[i],0); for(k=1;k<=m;k++) if(!solved[k]) { for(j=1;j<=a[0];j++) { if(a[j]<=ask[k]&&buc[ask[k]-a[j]][0]) solved[k]=1; } } for(j=1;j<=a[0];j++) buc[a[j]][0]=1,buc[a[j]][1]=0; } for(i=1;i<=b[0];i++) { buc[b[i]][0]=buc[b[i]][1]=0; } getsiz(x,0); for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) { tot=siz[to[i]]; root=0; getroot(to[i],0); work(root); } } int main() { scanf("%d%d",&n,&m); int i,x,y,z; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } for(i=1;i<=m;i++) { scanf("%d",&ask[i]); if(!ask[i]) solved[i]=1; } fag[0]=100000000; tot=n; getroot(1,0); work(root); for(i=1;i<=m;i++) { if(solved[i]) puts("Yes"); else puts("No"); } }
BZOJ_1316_樹上的詢問_點分治