社区讨论

求助(悬赏关注1,有注释)

P2414[NOI2011] 阿狸的打字机参与者 2已保存回复 3

讨论操作

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

当前回复
3 条
当前快照
1 份
快照标识符
@lo11jeuh
此快照首次捕获于
2023/10/22 13:41
2 年前
此快照最后确认于
2023/11/02 13:11
2 年前
查看原帖
先说一下问题吧,问题在于有一些询问并没有处理到,但是不知道为什么会有问题。 感谢
CPP
#include<bits/stdc++.h>
using namespace std;
int tree[100005][26];
int from[100005];
int fail[100005];
bool tail[100005];
int idtail[100005];
vector<int>mp[100005];
int ans[100005];
int ids=0;
int cnt=0;
/*
把sj的每个前缀的点标记一下,然后fail树上以si为根的子树求和
然后将j从小到大排序般打标记,由于输入比较特殊的原因,j从小到大排序后新的字符串一定可以通过上一次搞到
至于树上求子树和,可以dfn序列然后树状数组?大概就是单修区查? 
*/
void add(string s){
	int sz=s.size();
	int p=0; 
	for(int i=0;i<sz;i++){
		if(s[i]>='a'&&s[i]<='z'){
			int c=s[i]-'a';
			if(!tree[p][c]){
				cnt++;
				tree[p][c]=cnt;
				from[cnt]=p;
			}
			p=tree[p][c];
		}
		else if(s[i]=='P'){
			tail[p]=1;
			ids++;
			idtail[ids]=p;//表示第i个出现的字符串的尾巴的位值 
		}
		else{
			p=from[p];
		}
	}
}
void build(){
	queue<int>q;
	for(int i=0;i<26;i++){
		if(tree[0][i]){
			q.push(tree[0][i]);
		}
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(tree[u][i]){
				q.push(tree[u][i]);
				fail[tree[u][i]]=tree[fail[u]][i];
			}
			else{
				tree[u][i]=tree[fail[u]][i];
			}
		}
	}
	for(int i=1;i<=cnt;i++){
		int ffrom=fail[i];
		mp[ffrom].push_back(i);
	}
}
struct ak{
	int x;
	int y;
	int id;
}ask[100005];
bool cmp(ak x,ak y){
	return x.y<y.y;
}
int tk=0;
int dfn[100005];
int sz[100005];
void dfs(int x,int fa){
	dfn[x]=++tk;
	sz[dfn[x]]=1;
	for(int i=0;i<mp[x].size();i++){
		int to=mp[x][i];
		if(to==fa){
			continue;
		}
		dfs(to,x);
		sz[dfn[x]]+=sz[dfn[to]];
	}
}
int tr[100005];
int lowbit(int x){
	return x&(-x);
}
void ad(int pos,int val){
	for(int i=pos;i<=cnt;i+=lowbit(i)){
		tr[i]+=val;
	}
}
int query(int pos){
	int ret=0;
	for(int i=pos;i>=1;i-=lowbit(i)){
		ret+=tr[i];
	}
	return ret;
}
int onask=1;
void getans(string s){//我再走一遍s来模拟 
	int siz=s.size();
	int p=0; 
	for(int i=0;i<siz;i++){
		if(s[i]>='a'&&s[i]<='z'){//不管怎么样,现在肯定再走一个前缀 
			int c=s[i]-'a';
			p=tree[p][c];
			int df=dfn[p];
			ad(df,1);//在dfn上加上这个点 
			
		}
		else if(s[i]=='P'){//到达一个实串 
			while(p==idtail[ask[onask].y]){//现在正是在询问上 ,且在y串上 
				int xx=dfn[ask[onask].x];
				int r1=query(xx+sz[xx]-1);
				int r2=query(xx-1);
				ans[ask[onask].id]=r1-r2;
				onask++;
			}
		}
		else{//我正在回退 
			int df=dfn[p];
			ad(df,-1);//在dfn上加上这个点 
			p=from[p];
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	string s;
	cin >> s;
	add(s); 
	build();
	dfs(0,0);
	int m;
	cin >> m;
	for(int i=1;i<=m;i++){
		cin >> ask[i].x >> ask[i].y;
		ask[i].id=i;
	}
	sort(ask+1,ask+1+m,cmp);
	getans(s);//我再走一遍s来模拟 
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<endl;
	}
} 

回复

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

正在加载回复...