社区讨论

wa70求条

P14363[CSP-S 2025] 谐音替换参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mibfwacz
此快照首次捕获于
2025/11/23 16:12
3 个月前
此快照最后确认于
2025/11/23 17:31
3 个月前
查看原帖
哈希+trie+二维数点,不知道为啥错。求调
CPP
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define ull unsigned long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define sz(a) (int)a.size()
#define foru(a,b,c) for(int a=b;a<=c;a++)
#define ford(a,b,c) for(int a=b;a>=c;a--)
using namespace std;

const int N=5000005,Bas=13331,M=500005;
//const int inf=1e17;

int lb(int x){
	return x&-x;
}



//哈希 start ------------------------------------------------

struct _{
	string a1,a2;
	ull hah;
	int n;
	int p1,p2;
	
	void add(string s1,string s2){
		a1=s1;
		a2=s2;
	}
	
	ull doo(string s){
		ull res=0;
		int m=sz(s);
		foru(i,0,m-1){
			res=res*Bas+(s[i]-'a'+1);
		}
		return res;
	}
	
	string sub(string s,int l,int r){
		int n=sz(s);
		if(l>r||r>=n||l<0)
			return "";
		string res="";
		foru(i,l,r){
			res+=s[i];
		}
		return res;
	}
	
	void calc(){
		n=sz(a1);
		p1=0,p2=n-1;
		while(p1<=n-1){
			if(a1[p1]==a2[p1])
				p1++;
			else
				break;
		}//第一个不相等
		while(p2>=0){
			if(a1[p2]==a2[p2])
				p2--;
			else
				break;
		}//中间不同  将不同的部分 哈希呗   能替换只有不同的位置一样
		
		ull res=(doo(sub(a1,p1,p2))*Bas+'#')*Bas+doo(sub(a2,p1,p2));
		hah=res;
	}
	
	
}hh1[M],hh2[M];

// 哈希 end -----------------------------------

struct __{
	int w[N];
	void add(int x,int v){
		for(;x<N;x+=lb(x))
			w[x]+=v;
	}
	int qry(int x){
		int res=0;
		for(;x;x-=lb(x))
			res+=w[x];
		return res;
	}
}Bit;


//字典树 start ---------------------------------------------------------

int you[N][27];
int cnty;

int insy(string s){
	int p=0;
	int n=sz(s);
	foru(i,0,n-1){
		int t=s[i]-'a'+1;
		if(you[p][t]==0)
			you[p][t]=++cnty;
		p=you[p][t];
	}
	return p;//左边的树插入
}

int zuo[N][27];
int cntz;
int insz(string s){
	int p=0;
	int n=sz(s);
	foru(i,0,n-1){
		int t=s[i]-'a'+1;
		if(zuo[p][t]==0)
			zuo[p][t]=++cntz;
		p=zuo[p][t];
	}
	return p;//左边的树插入
}



//字典树 end-------------------------------------------------------------------





int dfl[N],dfr[N],siz[N],tim,posr[M],ans[M];
vector<vector<int> > dat(N),ques(N);
pii range[M];

void clr(){
	tim=0;
	foru(i,0,cnty){
		foru(j,1,26){
			you[i][j]=0;
		}
		siz[i]=0;
		dfl[i]=dfr[i]=0;
	}
	foru(i,0,cntz){
		foru(j,1,26){
			zuo[i][j]=0;
		}
		dat[i].clear();
		ques[i].clear();

	}
	cnty=cntz=0;
}


void dfsr(int u){
	dfl[u]=++tim;
	siz[u]=1;
	foru(i,1,26){
		if(you[u][i]){
			dfsr(you[u][i]);
			siz[u]+=siz[you[u][i]];
		}
	}
	dfr[u]=dfl[u]+siz[u]-1;
	
}


void dfsl(int u){
	for(auto id:dat[u]){
		int L=range[id].fi,R=range[id].se;
		Bit.add(L,1);
		Bit.add(R+1,-1);//处理询问  考虑以当前这个结尾的  被包含的点的个数
	}
	for(auto id:ques[u]){
		int pos=posr[id];
		ans[id]+=Bit.qry(pos);
	}
	foru(i,1,26){
		if(zuo[u][i]==0)
			continue;
		dfsl(zuo[u][i]);
	}
	for(auto id:dat[u]){
		int L=range[id].fi,R=range[id].se;
		Bit.add(L,-1);
		Bit.add(R+1,1);
	}
	
}


ull buc[N*2];
int cnt;
int n,q;
string s1[M],s2[M],t1[M],t2[M];
bool bd[M*2];
vector<vector<int> > g1(N*2),g2(N*2);

int gt(ll x){
	return lower_bound(buc+1,buc+1+cnt,x)-buc;
}


signed main(){
//------------------------------------------------------------------------------
//	freopen("replace4.in","r",stdin);
//	freopen("a.out","w",stdout);
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//------------------------------------------------------------------------------
//	hh1[1].add("xabcx","xadex");
//	hh1[1].calc();
//	dbge(hh1[1].hah);
//	dbge(hh1[1].p2);


	cin>>n>>q;
	foru(i,1,n){
		cin>>s1[i]>>s2[i];
		hh1[i].add(s1[i],s2[i]);
		hh1[i].calc();
		if(hh1[i].p1>hh1[i].p2)
            bd[i]=1;
		int nw=hh1[i].hah;
		buc[++cnt]=nw;
	}
//	q=1;
	foru(i,1,q){
		cin>>t1[i]>>t2[i];
		hh2[i].add(t1[i],t2[i]);
		hh2[i].calc();
		if(hh2[i].p1>hh2[i].p2)
			bd[i+n]=1;
		int nw=hh2[i].hah;
		buc[++cnt]=nw;
	}
//	foru(i,1,cnt){
//		cout<<buc[i]<<'\n';
//	}
//	dbg;
	sort(buc+1,buc+1+cnt);
	cnt=unique(buc+1,buc+1+cnt)-buc-1;
	foru(i,1,n){
		if(bd[i])
			continue;
		ull nw=hh1[i].hah;
		nw=gt(nw);
		g1[nw].pb(i);
	}
	foru(i,1,q){
		if(bd[i+n])
			continue;
		ull nw=hh2[i].hah;
		nw=gt(nw);
		g2[nw].pb(i);
	}
	
	
	
	foru(i,1,cnt){//把t插入  将右边插入  那么遍历左边的时候就要查询到根有多少个点
		//使得这些点的右边的dfs包含当前的右边的dfn   那么先插右边   在左边的地方丢vector  查询右边即可
		//有多少点可以Bit维护
		//插到右边需要维护每个的位置的dfn
		
		for(auto id:g2[i]){
			if(bd[id+n])
				continue;
			string s=hh2[id].a1;
			string t=hh2[id].sub(s,hh2[id].p2+1,hh2[id].n-1);
			posr[id]=insy(t);//询问  要找右边的点
			t=hh2[id].sub(s,0,hh2[id].p1-1);
			reverse(t.begin(),t.end());
			int pos=insz(t);//找左边的点在哪里
			ques[pos].pb(id);
		}
		
		for(auto id:g1[i]){
			if(bd[id])
				continue;
			string s=hh1[id].a1;
			string t=hh1[id].sub(s,hh1[id].p2+1,hh1[id].n-1);//小的串
			range[id].fi=insy(t);//右边的范围
			t=hh1[id].sub(s,0,hh1[id].p1-1);
			reverse(t.begin(),t.end());
			int pos=insz(t);//如果是0咋办呢
			dat[pos].pb(id);
		}
		dfsr(0);
		for(auto id:g1[i]){
			if(bd[id])
				continue;
			int pos=range[id].fi;
			range[id]={dfl[pos],dfr[pos]};//草插入的是反串啊
		}
		for(auto id:g2[i]){
			if(bd[id+n])
				continue;
			posr[id]=dfl[posr[id]];
		}
		dfsl(0);
		clr();
		
		
		
		
	}
	foru(i,1,q){
		cout<<ans[i]<<'\n';
	}
	



	return 0;


}
/*
bit不用清空啊


*/




回复

0 条回复,欢迎继续交流。

正在加载回复...