JSOI2008 火星人

传送门

这道题的话……首先得知道怎么求\(LCP\)。我们的方法首先二分一个长度,之后判断一下该区间内两段字符串的\(hash\)值是否相等,这样就可以啦。

然后本题还要求支持插入和修改字母,所以我们需要使用一棵\(splay\)来维护\(hash\)值。具体做法是动态维护每一个节点的子树的\(hash\)值,在合并的时候,有\(hash[x] = hash[l] \times base^{size[r]+1} + (s[x] - 'a') \times base^{size[r]} + hash[r]\),这样修改就可以了。

然后本题的建树可以直接建成完美的\(splay\),之后插入的时候先把要插入的位置\(splay\)出来之后插到右子树上。计算\(hash\)值的时候就\(splay\)一段区间出来取\(hash\)值就可以了。

做这道题的时候发现了长久以来的问题……更新的时候要先更新儿子后更新父亲……以前模板题怎么写都能过,但是这题先更新父亲会RE……debug了好久。注意在头尾各插入了一个无用字符,以防止出错。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define de putchar('#')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define B puts("GG")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int M = 200005;
const int N = 10000005;
const int INF = 1000000009;
const ull base = 47;
 
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 *= 10;
      ans += ch - '0';
      ch = getchar();
   }
   return ans * op;
}

struct node
{
   int fa,ch[2],size;
   ull hash,val;
   char c;
}t[M<<1];

int n,m,x,y,root,idx,cnt;
ull po[M];
char s[M],a[5];

bool get(int x)
{
   return t[t[x].fa].ch[1] == x;
}

void update(int x)
{
   int lson = t[x].ch[0],rson = t[x].ch[1];
   t[x].hash = t[lson].hash * po[t[rson].size+1] + t[x].val * po[t[rson].size] + t[rson].hash;
   t[x].size = t[lson].size + t[rson].size + 1;
}

void rotate(int x)
{
   int y = t[x].fa,z = t[y].fa,k = get(x);
   t[z].ch[get(y)] = x,t[x].fa = z;
   t[y].ch[k] = t[x].ch[k^1],t[t[y].ch[k]].fa = y;
   t[x].ch[k^1] = y,t[y].fa = x;
   update(y),update(x);
}

void splay(int x,int goal)
{
   while(t[x].fa != goal)
   {
      int y = t[x].fa,z = t[y].fa;
      if(z != goal) (t[y].ch[0] == x) ^ (t[z].ch[0] == y) ? rotate(x) : rotate(y);
      rotate(x);
   }
   if(!goal) root = x;
}

int build(int f,int l,int r)
{
   if(l > r) return 0;
   int mid = (l+r) >> 1,u = ++cnt;
   t[u].val = s[mid] - 'a' + 1,t[u].fa = f,t[u].c = s[mid];
   t[u].ch[0] = build(u,l,mid-1),t[u].ch[1] = build(u,mid+1,r);
   update(u);
   return u;
}

int find(int x)
{
   int u = root;
   while(1)
   {
      if(x <= t[t[u].ch[0]].size) u = t[u].ch[0];
      else if(x == t[t[u].ch[0]].size+1) return u;
      else x -= (t[t[u].ch[0]].size + 1),u = t[u].ch[1];
   }
}

void modify(int x)
{
   int g = find(x);
   splay(g,0),t[g].val = a[0] - 'a' + 1,t[g].c = a[0],update(g);
}

void insert(int x)
{
   int g = find(x),h = find(x+1);
   splay(g,0),splay(h,g);
   int u = ++idx;
   t[h].ch[0] = u,t[u].size = 1,t[u].val = t[u].hash = a[0] - 'a' + 1,t[u].fa = h;
   t[u].ch[0] = t[u].ch[1] = 0;
   update(h),update(g);
}

bool judge(int x,int y,int k)
{
   if(k == 0) return 1;
   int g = find(x-1),h = find(x+k);
   splay(g,0),splay(h,g);
   ull cur = t[t[h].ch[0]].hash;
   g = find(y-1),h = find(y+k);
   splay(g,0),splay(h,g);
   ull now = t[t[h].ch[0]].hash;
   return cur == now;
}

int query(int x,int y)
{
   int L = 0,R = idx,ans = 0;
   while(L <= R)
   {
      int mid = (L + R) >> 1;
      if(x + mid > idx || y + mid > idx) {R = mid - 1;continue;}
      if(judge(x,y,mid)) ans = mid,L = mid + 1;
      else R = mid - 1;
   }
   return ans;
}

int main()
{
   po[0] = 1;rep(i,1,M-2) po[i] = po[i-1] * base;
   scanf("%s",s+2),idx = strlen(s+2) + 2;
   s[1] = s[idx] = 'f',root = build(0,1,idx);
   m = read();
   rep(i,1,m)
   {
      scanf("%s",a),x = read() + 1;
      if(a[0] == 'Q') y = read() + 1,printf("%d\n",query(x,y));
      if(a[0] == 'R') scanf("%s",a),modify(x);
      if(a[0] == 'I') scanf("%s",a),insert(x);
   }  
   return 0;
}
 */
posted @ 2018-12-10 15:00  CaptainLi  阅读(169)  评论(0编辑  收藏  举报