考试题目——雪后村庄
题目描述
输入
输出
输出q行,每行一个字符串“yes”或“no”(不包括引号)。
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
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
提示
如果按着他的输入来做的话,你就炸了
由于每个车夫(lao si ji)的能力(fan che)值,只与某些路径中最小的那一段比较,还不需要保存,倍增和LCA来做铁定超时
这么多解决树上问题的姿势,为什么非要用这一种呢,并查集不也是解决这个问题很好的做法吗,将所有的边按边长从大到小排序,并将车夫(lao si ji)的能力(fan che)值从大到小排序,当某一次要处理的边小于了目前访问到的车夫(lao si ji)的能力(fan che)值,就先将这个车夫(lao si ji)的问题解决
时间复杂度:
这个n能不能优化掉呢?
yy到了哈希
将某一户人家,它在每个村子里的并查集编号,用哈希从一位数组压缩到一个整数
例:第i户人家,它在第j个村庄的并查集编号为x
即
由于
但有时候模下来会有重复,则使用双哈希,同一个哈希模另一个质数,如1e9+7
双哈希在NOIP中几乎无敌,不会有丧心病狂的卡双哈希的数据的
头一次写双哈希,WA了十几次,QwQ
AC代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define mod1 998244353
#define mod2 1000000007
#define maxn 200000
#define maxr 300000
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
struct node{
long long u,v,w,bl;
}road[maxr+5],dri[maxn+5];
inline bool cmp(node x,node y){return x.w>y.w;}
long long n,m,q,rd[maxn+5];
long long hash1[maxn+5],hash2[maxn+5],ksm1[maxn+5],ksm2[maxn+5];
long long fir[maxn+5],nxt[2*maxr+5],to[2*maxr+5],cnt;
long long f[maxn+5],sum[maxn+5],siz[maxn+5];
bool ans[maxn+5];
inline void dfs(long long x,long long ch,long long ne)
{
for(long long i=fir[x];i;i=nxt[i])
if(f[to[i]]==ne)
{
hash1[(to[i]-1)%m+1]=((hash1[(to[i]-1)%m+1]-(ne*ksm1[(to[i]-1)/m+1])%mod1)%mod1+mod1)%mod1;
hash1[(to[i]-1)%m+1]=(hash1[(to[i]-1)%m+1]+(ch*ksm1[(to[i]-1)/m+1])%mod1)%mod1;
hash2[(to[i]-1)%m+1]=((hash2[(to[i]-1)%m+1]-(ne*ksm2[(to[i]-1)/m+1])%mod2)%mod2+mod2)%mod2;
hash2[(to[i]-1)%m+1]=(hash2[(to[i]-1)%m+1]+(ch*ksm2[(to[i]-1)/m+1])%mod2)%mod2;
f[to[i]]=ch,siz[ch]++,siz[ne]--;
dfs(to[i],ch,ne);
}
}
inline void work(long long i)
{
long long u=road[i].u,v=road[i].v;
if(siz[f[u]]>=siz[f[v]])
{
hash1[(v-1)%m+1]=((hash1[(v-1)%m+1]-(f[v]*ksm1[(v-1)/m+1])%mod1)%mod1+mod1)%mod1;
hash1[(v-1)%m+1]=(hash1[(v-1)%m+1]+(f[u]*ksm1[(v-1)/m+1])%mod1)%mod1;
hash2[(v-1)%m+1]=((hash2[(v-1)%m+1]-(f[v]*ksm2[(v-1)/m+1])%mod2)%mod2+mod2)%mod2;
hash2[(v-1)%m+1]=(hash2[(v-1)%m+1]+(f[u]*ksm2[(v-1)/m+1])%mod2)%mod2;
long long hh=f[v];f[v]=f[u];dfs(v,f[u],hh);
siz[hh]--,siz[f[u]]++;
}
else
{
hash1[(u-1)%m+1]=((hash1[(u-1)%m+1]-(f[u]*ksm1[(u-1)/m+1])%mod1)%mod1+mod1)%mod1;
hash1[(u-1)%m+1]=(hash1[(u-1)%m+1]+(f[v]*ksm1[(u-1)/m+1])%mod1)%mod1;
hash2[(u-1)%m+1]=((hash2[(u-1)%m+1]-(f[u]*ksm2[(u-1)/m+1])%mod2)%mod2+mod2)%mod2;
hash2[(u-1)%m+1]=(hash2[(u-1)%m+1]+(f[v]*ksm2[(u-1)/m+1])%mod2)%mod2;
long long hh=f[u];f[u]=f[v];dfs(u,f[v],hh);
siz[hh]--,siz[f[v]]++;
}
}
inline void newnote(long long u,long long v){to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void init()
{
ksm1[1]=ksm2[1]=1;
for(long long i=2;i<=maxn;i++)
{
ksm1[i]=(ksm1[i-1]*(maxn+1)%mod1);
ksm2[i]=(ksm2[i-1]*(maxn+1)%mod2);
}
}
int main()
{
init();
long long i,j;
n=getint(),m=getint();
for(i=1;i<=n;i++)sum[i]=(rd[i]=getint())+sum[i-1];
for(i=1;i<=n;i++)
for(j=1;j<=rd[i];j++)
{
road[sum[i-1]+j].u=getint()+m*(i-1);
road[sum[i-1]+j].v=getint()+m*(i-1);
road[sum[i-1]+j].w=getint(),road[sum[i-1]+j].bl=i;
newnote(road[sum[i-1]+j].u,road[sum[i-1]+j].v);
newnote(road[sum[i-1]+j].v,road[sum[i-1]+j].u);
}
for(i=1;i<=n*m;i++)
{
f[i]=i,siz[i]=1;
hash1[(i-1)%m+1]=(hash1[(i-1)%m+1]+(i*ksm1[(i-1)/m+1]%mod1))%mod1;
hash2[(i-1)%m+1]=(hash2[(i-1)%m+1]+(i*ksm2[(i-1)/m+1]%mod2))%mod2;
}
sort(road+1,road+sum[n]+1,cmp);
q=getint();
for(i=1;i<=q;i++)
dri[i].u=getint(),dri[i].v=getint(),dri[i].w=getint(),dri[i].bl=i;
sort(dri+1,dri+q+1,cmp);
long long tmp=1;
for(i=1;i<=sum[n];i++)
{
while(road[i].w<dri[tmp].w&&tmp<=q)
{
if(hash1[dri[tmp].u]==hash1[dri[tmp].v]&&hash2[dri[tmp].u]==hash2[dri[tmp].v])
ans[dri[tmp].bl]=1;
tmp++;
}
if(f[road[i].u]!=f[road[i].v])work(i);
}
while(tmp<=q)
{
if(hash1[dri[tmp].u]==hash1[dri[tmp].v]&&hash2[dri[tmp].u]==hash2[dri[tmp].v])
ans[dri[tmp].bl]=1;
tmp++;
}
for(i=1;i<=q;i++)
if(ans[i])printf("yes\n");
else printf("no\n");
}