链接:等camp过后挂出来再加
题意:给一组n,m表示有一个长为n的未知的字符串S,并且有m组关系,每组关系给定x,y,l表示在串S中的以第x个字符开始长度为l的子串和以第y个字符开始长度为l的子串相等。n,m<=200000。
分析:首先暴力肯定是不可取的O(m*l),那么对于这种匹配式的统计该怎么办呢?首先要知道的时候加速匹配是肯定要的,怎么加速呢?我们将每一次的关系的l分成两部分2^k长度,就像rmq的询问那样,这样是可以等价的,那么我们就有了2*m个长度都是2的次方长度。那么我们从最大指数开始处理数据,我们设f(x,y,l)表示一组关系,现在l已经处理过了,那么如果有这样3组关系f(x,y,l),f(y,z,l),f(z,x,l)那么显然这3组之间是有冗余的数据的只要保留其二就可以了,那么我们有很多种这样的数据组,我们对同长度的所有的起点求最小生成树,这里用并查集和按秩合并O(n),然后在处理完2^k层的数据后我们把剩下的<n组数据处理到2^(k-1)层去,再继续处理,最后剩下的就是都是长度为1的关系啦,然后并查集搞搞就行了,总的时间复杂度为O(nlogn)。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=250000;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const int INF=2100000000;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
typedef unsigned long long uI64;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int tot,h[25],x[30*N],y[30*N],pre[30*N];
void add(int a,int b,int c) {
x[tot]=b;y[tot]=c;pre[tot]=h[a];h[a]=tot++;
}
int n,now,eve,fa[N],ra[N],bo[N];
int find_fa(int a) {
if (fa[a]==a) return a;
return fa[a]=find_fa(fa[a]);
}
int Union(int a,int b) {
a=find_fa(a);b=find_fa(b);
if (a==b) return 0;
if (ra[a]>ra[b]) fa[b]=a;
else {
fa[a]=b;
if (ra[a]==ra[b]) ra[a]++;
}
return 1;
}
void deal(int a) {
int i,tot=0;
eve=now;now^=1;
for (i=1;i<=n;i++) { fa[i]=i;ra[i]=0; }
for (i=h[a];i!=-1;i=pre[i])
if (Union(x[i],y[i])) {
if (a!=0) {
add(a-1,x[i],y[i]);add(a-1,x[i]+(1<<(a-1)),y[i]+(1<<(a-1)));
}
tot++;
if (tot>n) break ;
}
}
int main()
{
int i,k,m,a,b,c,mx;
ll ans;
while (scanf("%d%d", &n, &m)!=EOF) {
mx=tot=0;memset(h,-1,sizeof(h));
while (m--) {
scanf("%d%d%d", &a, &b, &c);
k=(int)log2(c);mx=max(mx,k);
add(k,a,b);add(k,a+c-(1<<k),b+c-(1<<k));
}
for (i=mx;i>=0;i--) deal(i);
for (i=1;i<=n;i++) { fa[i]=find_fa(i);bo[i]=0; }
ans=1LL;
for (i=1;i<=n;i++)
if (!bo[fa[i]]) { bo[fa[i]]=1;ans=(ans*26LL)%MOD; }
printf("%lld\n", (ans+MOD)%MOD);
}
return 0;
}
/*
5 5
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
8 3
1 4 3
3 4 1
4 6 3
15 2
1 6 3
2 9 7
*/
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=250000;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const int INF=2100000000;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
typedef unsigned long long uI64;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int tot,h[25],x[30*N],y[30*N],pre[30*N];
void add(int a,int b,int c) {
x[tot]=b;y[tot]=c;pre[tot]=h[a];h[a]=tot++;
}
int n,now,eve,fa[N],ra[N],bo[N];
int find_fa(int a) {
if (fa[a]==a) return a;
return fa[a]=find_fa(fa[a]);
}
int Union(int a,int b) {
a=find_fa(a);b=find_fa(b);
if (a==b) return 0;
if (ra[a]>ra[b]) fa[b]=a;
else {
fa[a]=b;
if (ra[a]==ra[b]) ra[a]++;
}
return 1;
}
void deal(int a) {
int i,tot=0;
eve=now;now^=1;
for (i=1;i<=n;i++) { fa[i]=i;ra[i]=0; }
for (i=h[a];i!=-1;i=pre[i])
if (Union(x[i],y[i])) {
if (a!=0) {
add(a-1,x[i],y[i]);add(a-1,x[i]+(1<<(a-1)),y[i]+(1<<(a-1)));
}
tot++;
if (tot>n) break ;
}
}
int main()
{
int i,k,m,a,b,c,mx;
ll ans;
while (scanf("%d%d", &n, &m)!=EOF) {
mx=tot=0;memset(h,-1,sizeof(h));
while (m--) {
scanf("%d%d%d", &a, &b, &c);
k=(int)log2(c);mx=max(mx,k);
add(k,a,b);add(k,a+c-(1<<k),b+c-(1<<k));
}
for (i=mx;i>=0;i--) deal(i);
for (i=1;i<=n;i++) { fa[i]=find_fa(i);bo[i]=0; }
ans=1LL;
for (i=1;i<=n;i++)
if (!bo[fa[i]]) { bo[fa[i]]=1;ans=(ans*26LL)%MOD; }
printf("%lld\n", (ans+MOD)%MOD);
}
return 0;
}
/*
5 5
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
8 3
1 4 3
3 4 1
4 6 3
15 2
1 6 3
2 9 7
*/