BZOJ1316 树上的询问

Time Limit: 10 Sec Memory Limit: 162 MB

Description

一棵\(n\)个点的带权有根树,有\(p\)个询问,每次询问树中是否存在一条长度为\(Len\)的路径,如果是,输出\(Yes\)否输出\(No\).

Input

第一行两个整数\(n, p\)分别表示点的个数和询问的个数. 接下来\(n-1\)行每行三个数\(x, y, c\),表示有一条树边\(x\rightarrow y\),长度为\(c\). 接下来\(p\)行每行一个数\(Len\),表示询问树中是否存在一条长度为\(Len\)的路径.

Output

输出有\(p\)行,YesNo.

Sample Input

6 4 
1 2 5 
1 3 7 
1 4 1 
3 5 2 
3 6 3 
1 
8 
13 
14 

Sample Output

Yes 
Yes 
No 
Yes 

HINT

\(30\%\)的数据,\(n\leq100\)
\(100\%\)的数据,\(n\leq10000\)\(p\leq100\),长度\(\leq 1000000\)
做完此题可看下POJ 3237 Tree

Soultion

一开始看到这道题就想到点分治,但是发现有那么多不一样的询问,以为要用fft。然后看见边权的域太大,肯定不行。然后又看到数据范围,\(p\leq100\),暴力枚举询问即可。那么这道题就是点分治模板题,不说什么。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{
	const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;
	#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
	inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
	inline void putc(char x){*oS++=x;if(oS==oT)flush();}
	template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}
	template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}
	inline void print(const char *s){while(*s!='\0')putc(*s++);}
	struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}

const int N=10000+7;
int n,Q,x,y,z,q[N],rt,sum,mima,num[N],vis[N],dist[N],p[N],hd,tl,f[N],ans[N];map<int,int>s,t;
struct Edge{int to,ne,w;}g[N<<1];int head[N],tot;
inline void Addedge(int x,int y,int z){g[++tot].to=y;g[tot].w=z;g[tot].ne=head[x];head[x]=tot;}

inline void Getroot(int x,int fa=0){
	num[x]=1;int f=0;
	for(register int i=head[x];i;i=g[i].ne){
		int y=g[i].to;if(y==fa||vis[y])continue;
		Getroot(y,x);num[x]+=num[y];SMAX(f,num[y]);
	}
	SMAX(f,sum-num[x]);if(SMIN(mima,f))rt=x;
}
inline void BFS(int x,int fa){
	p[hd=0,tl=1]=x;f[x]=fa;
	while(hd<tl){
		x=p[++hd];t[dist[x]]++;
		for(register int i=head[x];i;i=g[i].ne){
			int y=g[i].to;if(vis[y]||y==f[x])continue;//错误笔记:if中间是||不是&&!!! 
			dist[y]=dist[x]+g[i].w;p[++tl]=y;f[y]=x;
		}
	}
}
inline void Calc(int x){
	s.clear();s[0]=1;
	for(register int i=head[x];i;i=g[i].ne){
		int y=g[i].to;if(vis[y])continue;
		t.clear();dist[y]=g[i].w;BFS(y,x);
		for(register int j=1;j<=Q;++j)if(!ans[j])
			for(register int k=1;k<=tl;++k){
				if(q[j]>=dist[p[k]]&&s.count(q[j]-dist[p[k]])){ans[j]=1;break;}
			}
		for(register int i=1;i<=tl;++i)s[dist[p[i]]]++;
	}
}
inline void Solve(int x){
	vis[x]=1;Calc(x);
	for(register int i=head[x];i;i=g[i].ne){
		int y=g[i].to;if(vis[y])continue;
		mima=sum=num[y];Getroot(y);Solve(rt);
	}
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("BZOJ1316.in","r",stdin);freopen("BZOJ1316.out","w",stdout);
#endif
	read(n),read(Q);for(register int i=1;i<n;++i)read(x),read(y),read(z),Addedge(x,y,z),Addedge(y,x,z);//错误笔记:记得建两条边 
	for(register int i=1;i<=Q;++i)read(q[i]),q[i]==0?ans[i]=1:0;
	mima=sum=n;Getroot(1);Solve(rt);
	for(register int i=1;i<=Q;++i)print(ans[i]?"Yes\n":"No\n");
}
posted @ 2018-10-25 19:32  hankeke303  阅读(159)  评论(0编辑  收藏  举报