2017.8.15 阿狸的打字机 失败总结

来源:互联网 发布:linux arp表老化时间 编辑:程序博客网 时间:2024/05/19 16:27

        好难啊,这个题需要很强的技巧和码力

        首先ac自动机不难想到,暴力跳fail也不难想到,但建fail树没想到

        建好之后问题就变成了随着点的加入,求一个子树里1的个数

        然后由于询问一定在一个子树里,而加点的时候合法的一定在内部(dfs序内部),所以差分即可求一段中1的和,可用树状数组加速

     


    码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<vector>using namespace std;#define N 200010int sz=1,T=1,len,t[N],i,x,y,l[N],r[N],ch[N][27],ans[N],ci[N],fu[N],sp[N],m;char str[N];queue<int>q;vector<int>v[100005],wen[100005],id[100005];int lowbit(int a){return a&(-a);}void add(int x,int y){int i;for(i=x;i<=T;i+=lowbit(i)){       t[i]+=y;}}int qiu(int x){int ans=0,i;for(i=x;i>0;i-=lowbit(i)){ans+=t[i];}return ans;}void jia(){int i,o=1,lin=0;for(i=0;i<len;i++)if(str[i]=='P')  ci[++lin]=o;elseif(str[i]=='B')  o=fu[o];else{if(ch[o][str[i]-'a'+1]==0)ch[o][str[i]-'a'+1]=++sz,fu[sz]=o;o=ch[o][str[i]-'a'+1];}}void shipei(){int i;q.push(1);while(!q.empty()){int st=q.front();q.pop();for(i=1;i<=26;i++){if(ch[st][i]==0)continue;int k=sp[st];while(ch[k][i]==0)k=sp[k];sp[ch[st][i]]=ch[k][i];q.push(ch[st][i]);}}}void dfs(int o){l[o]=++T;for(int i=0;i<v[o].size();i++)dfs(v[o][i]);r[o]=++T;}void work(){int o=1,dc=0;add(l[1],1);for(int j=0;j<len;j++)if(str[j]=='P'){++dc;for(i=0;i<wen[dc].size();i++){int x=ci[wen[dc][i]];ans[id[dc][i]]=qiu(r[x])-qiu(l[x]-1);}}else if(str[j]=='B')add(l[o],-1),o=fu[o];else{o=ch[o][str[j]-'a'+1];add(l[o],1);}}int main(){for(i=1;i<=26;i++)      ch[0][i]=1;           scanf("%s",str);len=strlen(str);    jia();shipei();    for(i=1;i<=sz;i++)    v[sp[i]].push_back(i);scanf("%d",&m);for(i=1;i<=m;i++){scanf("%d%d",&x,&y);wen[y].push_back(x);id[y].push_back(i);}dfs(1);work();for(i=1;i<=m;i++)printf("%d\n",ans[i]);} 


       

原创粉丝点击