LOJ#2303. 「NOI2017」蚯蚓排队 hash+链表
正常来说,单次操作的复杂度是 $O(k^2)$,然后整体复杂度是 $O(nk^2)$.
但是我们发现每次合并两个蚯蚓的复杂度的极限是 $O( min(size_{min},50) \times 50)$.
然后根据启发式合并的复杂度分析,即使要求遍历完 $size_{min}$,复杂度最高也就是 $O(n \log n k)$.
这个的极限也就是 $O(10^8)$ 左右,再加上跑不满那个 $O(\log n)$,实际运行速度比较快.
存储哈希值和合并蚯蚓用的都是链表.
可以开两个模数,一个小于 $10^7$,一个是 $998244353$,速度应该比 $map$ 之类的快一点.
code:
#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200009
#define ll long long
#define MA 9999071
#define MB 998244353
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int A=233;
const int B=2333;
int n,m,edges,cnt;
int ST[N],ED[N],SIZE[N];
int BA[200000],BB[200000];
int hd[MA+233],nex[N*100];
int val[N*100],si[N*100];
char str[10000008];
int seqa[10000008];
int seqb[10000008];
struct data {
int v,l,r;
}a[N];
int find(int x,int y) {
++cnt;
for(int i=hd[x];i;i=nex[i]) {
if(val[i]==y) return 1;
}
return 0;
}
void upd(int x,int y,int d) {
++cnt;
for(int i=hd[x];i;i=nex[i]) {
++cnt;
if(val[i]==y) {
si[i]+=d;
return;
}
}
}
int query(int x,int y) {
++cnt;
for(int i=hd[x];i;i=nex[i]) {
if(val[i]==y) return si[i];
}
return 0;
}
void ins(int x,int y) {
++cnt;
if(find(x,y)) {
upd(x,y,1);
}
else {
nex[++edges]=hd[x];
hd[x]=edges,val[edges]=y,si[edges]=1;
}
}
void del(int x,int y) {
upd(x,y,-1);
}
void init() {
BA[0]=BB[0]=1;
for(int i=1;i<2000;++i) {
BA[i]=(ll)BA[i-1]*A%MA;
BB[i]=(ll)BB[i-1]*B%MB;
}
}
void merge(int x,int y) {
x=ST[x];
int ex=ED[x],ey=ED[y];
int len=1,ha=0,hb=0;
for(int i=ex;len<=50&&i;i=a[i].l) {
ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA;
hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB;
int hta=ha;
int htb=hb;
for(int j=y,p=len+1;j&&p<=50;j=a[j].r) {
hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA;
htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB;
ins(hta,htb);
++p;
}
++len;
}
a[ex].r=y;
a[y].l=ex;
ST[ED[y]]=x;
ED[x]=ED[y];
}
void split(int x) {
int y=a[x].r;
int ra=rand(),sx,ex=x,sy=y,ey;
if(ra&1) {
for(ey=y;a[ey].r;ey=a[ey].r);
sx=ST[ey];
}
else {
for(sx=x;a[sx].l;sx=a[sx].l);
ey=ED[sx];
}
int len=1,ha=0,hb=0;
for(int i=ex;len<=50&&i;i=a[i].l) {
ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA;
hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB;
int hta=ha;
int htb=hb;
for(int j=y,p=len+1;j&&p<=50;j=a[j].r) {
++cnt;
hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA;
htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB;
del(hta,htb);
++p;
}
++len;
}
a[x].r=0;
a[y].l=0;
ED[sx]=x;
ST[x]=sx,ED[x]=x;
ST[ey]=y;
ED[y]=ey,ST[y]=y;
}
int main() {
// setIO("input");
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n;++i) {
scanf("%d",&a[i].v);
ED[i]=ST[i]=i,SIZE[i]=1;
a[i].l=a[i].r=0;
ins((ll)a[i].v*A%MA,(ll)a[i].v*B%MB);
}
int x,y,z;
for(int T=1;T<=m;++T) {
int op;
scanf("%d",&op);
if(op==1) {
scanf("%d%d",&x,&y);
merge(x,y);
}
if(op==2) {
scanf("%d",&x);
split(x);
}
if(op==3) {
int k,len;
scanf("%s%d",str+1,&k);
len=strlen(str+1);
seqa[0]=seqb[0]=0;
for(int i=1;i<=len;++i) {
seqa[i]=(ll)((ll)seqa[i-1]*A%MA+(ll)(str[i]-'0')*A%MA)%MA;
seqb[i]=(ll)((ll)seqb[i-1]*B%MB+(ll)(str[i]-'0')*B%MB)%MB;
}
int ans=1;
for(int i=k;i<=len;++i) {
int ca=(ll)(seqa[i]-(ll)seqa[i-k]*BA[k]%MA+MA)%MA;
int cb=(ll)(seqb[i]-(ll)seqb[i-k]*BB[k]%MB+MB)%MB;
ans=(ll)ans*query(ca,cb)%998244353;
}
printf("%d\n",ans);
}
}
return 0;
}

浙公网安备 33010602011771号