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\)行,Yes
或No
.
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");
}