BZOJ2555 Substring

传送门

朴素的想法是直接用SAM模拟,但是这样的话每次归并排序会T掉……

考虑到每次的影响,对于初始的SAM来说,我们每次新加入一个点,那么就会使这个点到\(t_0\)状态的路径上所有的点全部权值+1,于是我们需要维护路径,同时还需要支持动态插入,那就是LCT了。

于是乎我们需要用LCT来维护SAM的parent树,其实也不是很难……就是每次在SAM更改parent树的时候LCT照着做就行了。因为这题树不会有什么换根之类的乱七八糟的东西,所以不需要\(reverse\),不需要\(makeroot\)……(orz LCT都快忘光了)

然后也不需要pushup(你也不用维护子树信息啊_) 直接每次在修改的时候打个标记pushdown就好了。

最后要注意的一点是,在query的时候如果没有匹配要直接退出。然后如果匹配到的话需要先把这个节点splay到根再计算。

#include<bits/stdc++.h>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 600005;
const int N = 3000005;
const int INF = 2147483647;

int read()
{
   int ans = 0,op = 1;
   char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

int Q,n,mask;
char s[N];
string chars;

void gets(int mask)
{
   scanf("%s",s),chars = s;
   int k = chars.length()-1;
   rep(j,0,k)
   {
      mask = (mask * 131 + j) % chars.length();
      char t = chars[j];
      chars[j] = chars[mask],chars[mask] = t;
   }
}

struct LCT
{
   int ch[M<<1][2],tag[M<<1],val[M<<1],fa[M<<1],top,sta[M<<1];
   bool get(int x) {return ch[fa[x]][1] == x;}
   bool nroot(int x) {return (ch[fa[x]][1] == x) || (ch[fa[x]][0] == x);}
   void add(int x,int y) {if(x) val[x] += y,tag[x] += y;}
   void pushdown(int x)
   {
      if(tag[x] != 0)
      {
	 int l = ch[x][0],r = ch[x][1];
	 add(l,tag[x]),add(r,tag[x]),tag[x] = 0;
      }
   }
   void rotate(int x)
   {
      int y = fa[x],z = fa[y],k = get(x);
      if(nroot(y)) ch[z][get(y)] = x;
      fa[x] = z,ch[y][k] = ch[x][k^1],fa[ch[x][k^1]] = y;
      ch[x][k^1] = y,fa[y] = x;
   }
   void splay(int x)
   {
      top = 0;
      int p = x;
      sta[++top] = p;
      while(nroot(p)) p = fa[p],sta[++top] = p;
      while(top) pushdown(sta[top--]);
      while(nroot(x))
      {
	 int y = fa[x],z = fa[y];
	 if(nroot(y)) ((ch[z][0] == y) ^ (ch[y][0] == x)) ? rotate(x) : rotate(y);
	 rotate(x);
      }
   }
   void access(int x) {for(int t = 0;x;t = x,x = fa[x]) splay(x),ch[x][1] = t;}
   void link(int x,int y)
   {
      fa[x] = y;
      access(y),splay(y),add(y,val[x]);
   }
   void cut(int x)
   {
      access(x),splay(x);
      add(ch[x][0],-val[x]);
      fa[ch[x][0]] = 0,ch[x][0] = 0;
   }
}T;

struct Suffix
{
   int last,cnt,ch[M<<1][26],fa[M<<1],l[M<<1];
   void extend(int c)
   {
      int p = last,np = ++cnt;
      l[np] = l[p] + 1,last = cnt,T.val[np] = 1;
      while(p && !ch[p][c]) ch[p][c] = np,p = fa[p];
      if(!p) {fa[np] = 1,T.link(np,1);return;}
      int q = ch[p][c];
      if(l[q] == l[p] + 1) fa[np] = q,T.link(np,q);
      else
      {
	 int nq = ++cnt;
	 l[nq] = l[p] + 1,memcpy(ch[nq],ch[q],sizeof(ch[q]));
	 fa[nq] = fa[q],T.link(nq,fa[q]);
	 fa[np] = fa[q] = nq,T.cut(q),T.link(np,nq),T.link(q,nq);
	 while(ch[p][c] == q) ch[p][c] = nq,p = fa[p];
      }
   }
   void add()
   {
      gets(mask);
      int d = chars.length()-1;
      rep(i,0,d) extend(chars[i] - 'A');
   }
   int query()
   {
      gets(mask);
      int d = chars.length()-1,u = 1;
      rep(i,0,d)
      {
	 int c = chars[i] - 'A';
	 if(!ch[u][c]) return 0;
	 u = ch[u][c];
      }
      T.splay(u);
      return T.val[u];
   }
}SAM;

int main()
{
   Q = read(),SAM.last = SAM.cnt = 1;
   scanf("%s",s+1),n = strlen(s+1);
   rep(i,1,n) SAM.extend(s[i] - 'A');
   while(Q--)
   {
      scanf("%s",s);
      if(s[0] == 'A') SAM.add();
      else
      {
	 int ans = SAM.query();
	 printf("%d\n",ans),mask ^= ans;
      }
   }
   return 0;
}

当你意识到,每个上一秒都成为永恒。
posted @ 2019-01-14 22:53  CaptainLi  阅读(79)  评论(0编辑  收藏  举报