luogu4770 [NOI2018]你的名字 (SAM+主席树)

对S建SAM,拿着T在上面跑

跑的时候不仅无法转移要跳parent,转移过去不在范围内也要跳parent(注意因为范围和长度有关,跳的时候应该把长度一点一点地缩)

这样就能得到对于T的每个前缀,它最长的不合法的后缀的长度ill[i]

得到他要去重,以后可以再对T建SAM,然后对于每个节点,$ans+=max(0,len[i]-max(len[fa[i]],ill[pos[i]]))$,其中pos[i]是它的right集合中随便一个位置(因为每个位置的小于len的ill都一样)

那么怎么判在不在范围内呢..似乎可以线段树合并,带个log地求出每个节点的right

当然也可以直接dfs序然后建主席树

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 #define MP make_pair
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=1e6+10;
  8 
  9 inline char gc(){
 10     return getchar();
 11     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
 12     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
 13 }
 14 inline ll rd(){
 15     ll x=0;char c=gc();bool neg=0;
 16     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
 17     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
 18     return neg?(~x+1):x;
 19 }
 20 
 21 struct SAM{
 22     int len[maxn*2],fa[maxn*2],tr[maxn*2][26],pct,lst,pos[maxn*2];
 23     
 24     inline void clear(){
 25         while(pct){
 26             CLR(tr[pct],0);
 27             len[pct]=fa[pct]=pos[pct]=0;
 28             pct--;
 29         }pct=lst=1;
 30     }
 31     
 32     inline void insert(int x,bool b){
 33         int p=++pct;
 34         len[p]=len[lst]+1;pos[p]=len[p];
 35         int o=lst;lst=p;
 36         for(;o&&!tr[o][x];o=fa[o]) tr[o][x]=p;
 37         if(!o){fa[p]=1;return;}
 38         int q=tr[o][x];
 39         if(len[q]==len[o]+1){fa[p]=q;return;}
 40         int qq=++pct;if(b) pos[qq]=pos[p];
 41         len[qq]=len[o]+1;fa[qq]=fa[q];
 42         memcpy(tr[qq],tr[q],sizeof(tr[q]));
 43         fa[q]=fa[p]=qq;
 44         for(;o&&tr[o][x]==q;o=fa[o]) tr[o][x]=qq;
 45     }
 46 }S,T;
 47 
 48 char s[maxn];
 49 int N,M,Q;
 50 int ill[maxn];
 51 int cnt[maxn],rnk[maxn],dfn[maxn][2],id[maxn],tot;
 52 vector<int> eg[maxn];
 53 
 54 inline void dfs(int x){
 55     id[++tot]=x;dfn[x][0]=tot;
 56     for(int i=0;i<eg[x].size();i++) dfs(eg[x][i]);
 57     dfn[x][1]=tot;
 58 }
 59 
 60 int rt[maxn],num[maxn*20],ch[maxn*20][2],pct;
 61 
 62 inline void insert(int pre,int &p,int l,int r,int x,int y){
 63     p=++pct;num[p]=num[pre]+y;
 64     if(l<r){
 65         int m=l+r>>1;
 66         if(x<=m) insert(ch[pre][0],ch[p][0],l,m,x,y),ch[p][1]=ch[pre][1];
 67         else insert(ch[pre][1],ch[p][1],m+1,r,x,y),ch[p][0]=ch[pre][0];
 68     }
 69 }
 70 
 71 inline int query(int pre,int p,int l,int r,int x,int y){
 72     if(x>y) return 0;
 73     if(x<=l&&r<=y) return num[p]-num[pre];
 74     int m=l+r>>1,re=0;
 75     if(x<=m) re=query(ch[pre][0],ch[p][0],l,m,x,y);
 76     if(y>=m+1) re+=query(ch[pre][1],ch[p][1],m+1,r,x,y);
 77     return re;
 78 }
 79 
 80 int main(){
 81     //freopen("","r",stdin);
 82     int i,j,k;
 83     scanf("%s",s+1);N=strlen(s+1);
 84     S.clear();
 85     for(i=1;i<=N;i++) S.insert(s[i]-'a',0);
 86         
 87     for(i=2;i<=S.pct;i++) eg[S.fa[i]].push_back(i);
 88     dfs(1);
 89     for(i=1;i<=tot;i++){
 90         if(S.pos[id[i]]) insert(rt[i-1],rt[i],1,N,S.pos[id[i]],1);
 91         else rt[i]=rt[i-1]; 
 92     }
 93         
 94     Q=rd();
 95     for(i=1;i<=Q;i++){
 96         scanf("%s",s+1);M=strlen(s+1);
 97         int l=rd(),r=rd();
 98         int now=1,nl=0;
 99         for(j=1;j<=M;j++){
100             int x=s[j]-'a';
101             while(now&&!(S.tr[now][x]&&query(rt[dfn[S.tr[now][x]][0]-1],rt[dfn[S.tr[now][x]][1]],1,N,l+nl,r))){
102                 if(!nl){now=0;break;}
103                 nl--;
104                 if(nl==S.len[S.fa[now]]) now=S.fa[now];
105             }
106             if(now) nl++,now=S.tr[now][x];
107             else now=1; 
108             ill[j]=nl;
109             // printf("~%d %d\n",j,ill[j]);
110         }
111         T.clear();
112         for(j=1;j<=M;j++) T.insert(s[j]-'a',1);
113         ll ans=0;
114         for(j=2;j<=T.pct;j++){
115             ans+=max(0,T.len[j]-max(T.len[T.fa[j]],ill[T.pos[j]]));
116         }
117         printf("%lld\n",ans);
118     }
119     return 0;
120 }

猜你喜欢

转载自www.cnblogs.com/Ressed/p/10205523.html