题目描述
输入
输出
输出q行,每行一个字符串“yes”或“no”(不包括引号)。
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
2 4
3 4
1 2 3
2 3 2
2 4 4
1 2 3
1 3 2
2 3 2
3 4 4
4
1 3 3
1 3 2
1 4 3
3 4 4
样例输出
no
yes
no
no
提示
其实我真正想写的是这道题啦……
乍一看,求瓶颈边!只要判断每个村庄中a、b瓶颈边是否小于等于k就可以了,所以使用Kruskal树来做!
但是询问和村庄数都很多,这使得q次就是q*n,无法跑过1s(废话)
那么怎么办呢?注意到其实题目并不是让我们求瓶颈边,而是判断瓶颈边是否小于等于k,或者这样说:判断只使用小于等于k的边能否使a和b连通。
我们考虑离线算法,将询问当成边一起做。使用并查集维护连通性,遇到询问时只需要判断每个村庄的a、b是否在同一并查集即可。但是这样仍然是q*n,会TLE(废话,要判断n次)。
我们考虑利用启发式合并暴力合并并查集,让每个点直接指向根节点(其实就是集合标号),合并时让节点少的标号修改成节点多的,平均复杂度便是log(n*m)。用一个hash表记录每个节点在不同村庄的集合,判断时只需要判断a和b的hash值是否相等即可。最后优化一下常数、写一写读入优化神马的,可以跑进1s。
代码如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define mod2 998244353
#define N 200005
#define M 500005
int m,n,p,q,line[N];
int Set[N],sum[N];//属于哪个集合、集合中的元素个数
int hash[N];//每个元素的哈希值
int f[N],f2[N],fir[N],nex[N];
int ans[N];
void read(int &p)
{
p=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')p=p*10+c-'0',c=getchar();
}
struct node
{
int s,t,l,w;
bool operator<(node b)const
{
return l==b.l?w<b.w:l>b.l;
}
}A[M];
void upd(int a,int k)//将a号点标号变成k O(1)
{
int w=(a-1)%m+1,p=(a-1)/m;
hash[w]=((hash[w]+1ll*(k-Set[a])*f[p]%mod2)%mod2+mod2)%mod2;
//hash2[w]=((hash2[w]+1ll*(k-Set[a])*f2[p]%mod)%mod+mod)%mod;
Set[a]=k;
}
bool cmp(node a,node b)
{
if(!a.w)
return 0;
if(!b.w)
return 1;
return a.w<b.w;
}
int main()
{
read(n);read(m);
for(int i=1;i<=n;i++)//200000
read(line[i]);
f[0]=1;
for(int i=1;i<=n;i++)//200000
f[i]=1ll*f[i-1]*7%mod2;
for(int i=1;i<=n;i++)//200000
{
for(int j=1;j<=line[i];j++)
{
read(A[p+j].s);read(A[p+j].t);read(A[p+j].l);
A[p+j].s+=(i-1)*m;
A[p+j].t+=(i-1)*m;
}
p+=line[i];
}
for(int i=1;i<=n*m;i++)//200000
{
upd(i,i);
sum[i]=1;
fir[i]=i;
}
read(q);
for(int i=1;i<=q;i++)
{
read(A[p+i].s);read(A[p+i].t);read(A[p+i].l);
A[p+i].w=i;
}
p+=q;
sort(A+1,A+p+1);
int x,y;
for(int i=1;i<=p;i++)
{
x=Set[A[i].s];
y=Set[A[i].t];
if(!A[i].w)
{
if(x!=y)
{
if(sum[x]>sum[y])
swap(x,y);
int j;
for(j=fir[x];;j=nex[j])
{
upd(j,y);
if(!nex[j])
break;
}
nex[j]=fir[y];
fir[y]=fir[x];
sum[y]+=sum[x];
}
}
else
ans[A[i].w]=hash[A[i].s]==hash[A[i].t];
}
for(int i=1;i<=q;i++)
{
if(ans[i])
printf("yes\n");
else
printf("no\n");
}
}