zoukankan      html  css  js  c++  java
  • Luogu P4036 火星人

    题目大意

    对于一个小写字母组成的字符串,有 (m) 种操作。

    1. ( exttt{L} ext{ }x ext{ }y) :询问分别从第 (x) 位、第 (y) 位开始的子串的最长公共前缀长度。
    2. ( exttt{R} ext{ }x ext{ }d) :将第 (x) 位的字符修改为 (d)
    3. ( exttt{I} ext{ }x ext{ }d) :在第 (x) 位后插入字符 (d)

    其中,字符串长度 (L) 始终满足 (1 leq L leq 10^5) ,且字符串始终由小写字母组成, (1 leq n leq 1.5 imes 10^5) ,询问的操作个数不超过 (10^4) 个。

    题解

    容易想到,对于每一段子串可以用 Hash 进行比较。
    ([x,x+k))([y,y+k)) 相同,则 ([x,x+k-1))([y,y+k-1)) 一定相同。
    ([x,x+k))([y,y+k)) 不相同,则 ([x,x+k+1))([y,y+k+1)) 一定不相同。
    显然我们可以用二分来做。
    然而这一题还需要支持修改和插入操作,我们可以用平衡树来维护每一个点的 Hash 值。
    设点 (i) 的 Hash 值为 (H(i)) ,左儿子为 (l_i) ,右儿子为 (r_i) ,子树大小为 (size(i)) ,对应的字母为 (val_i)
    (H(i) = H(l_i) imes base^{size(r_i)+1} + val_i imes base^{size(r_i)} + H(r_i))
    unsigned int + 自然溢出就好,取模太慢了。
    代码自带大常数,开了 O2 才A。
    听说 Splay 跑得比 FHQ Treap 快,但是不想打。。。

    #include <cstdio>
    #include <cstdlib>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    
    using std::swap;
    
    #define MAX_N (100000 + 5)
    #define MAX_M (150000 + 5)
    
    struct FHQ_Treap
    {
    	int ch[2];
    	int prior;
    	unsigned val;
    	unsigned hash;
    	int size;
    };
    
    const unsigned base = 27;
    
    int T;
    char s[MAX_N];
    int n, m;
    int root, len;
    FHQ_Treap t[MAX_N + MAX_M];
    unsigned p[MAX_N + MAX_M];
    
    int ReadInt()
    {
    	int res = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) res = res * 10 + ch - '0', ch = getchar();
    	return res;
    }
    
    char ReadChar()
    {
    	char ch = getchar();
    	while (!isalpha(ch)) ch = getchar();
    	return ch;
    }
    
    int newNode(int val)
    {
    	t[++len].prior = rand();
    	t[len].ch[0] = t[len].ch[1] = 0;
    	t[len].val = t[len].hash = val;
    	t[len].size = 1;
    	return len;
    }
    
    void Update(int idx)
    {
    	int l = t[idx].ch[0], r = t[idx].ch[1];
    	t[idx].size = t[l].size + t[r].size + 1;
    	t[idx].hash = t[l].hash * p[t[r].size + 1] + t[idx].val * p[t[r].size] + t[r].hash;
    }
    
    void Split(int idx, int rk, int & L, int & R)
    {
    	if (!idx)
    	{
    		L = R = 0;
    		return;
    	}
    	if (t[t[idx].ch[0]].size + 1 <= rk)
    	{
    		L = idx;
    		Split(t[idx].ch[1], rk - t[t[idx].ch[0]].size - 1, t[L].ch[1], R);
    	}
    	else
    	{
    		R = idx;
    		Split(t[idx].ch[0], rk, L, t[R].ch[0]);
    	}
    	Update(idx);
    }
    
    int Merge(int L, int R)
    {
    	if (!L || !R) return L + R;
    	if (t[L].prior < t[R].prior)
    	{
    		t[L].ch[1] = Merge(t[L].ch[1], R);
    		Update(L);
    		return L;
    	}
    	else
    	{
    		t[R].ch[0] = Merge(L, t[R].ch[0]);
    		Update(R);
    		return R;
    	}
    }	
    
    unsigned Query(int l, int r)
    {
    	int L, M, R;
    	unsigned res;
    	Split(root, r, L, R);
    	Split(L, l - 1, L, M);
    	res = t[M].hash;
    	root = Merge(Merge(L, M), R); 
    	return res;
    }
    
    void Modify(int rk, unsigned val)
    {
    	int L, M, R;
    	Split(root, rk - 1, L, R);
    	Split(R, 1, M, R);
    	t[M].val = t[M].hash = val;
    	root = Merge(Merge(L, M), R);
    }
    
    void Insert(int rk, unsigned val)
    {
    	int L, R;
    	Split(root, rk, L, R);
    	root = Merge(Merge(L, newNode(val)), R);
    }
    
    int main()
    {
    	srand(19260817);
    	p[0] = 1;
    	for (int i = 1; i < MAX_N + MAX_M; ++i)
    	{
    		p[i] = p[i - 1] * base;
    	}
    	T = ReadInt();
    	while (T--)
    	{
    		root = len = 0;
    		scanf("%s", s + 1);
    		m = ReadInt();
    		n = strlen(s + 1);
    		for (int i = 1; i <= n; ++i)
    		{
    			root = Merge(root, newNode(s[i] - 'a' + 1));
    		}
    		char ch, d;
    		int x, y, l, r, mid, ans;
    		while (m--)
    		{
    			ch = ReadChar();
    			switch (ch)
    			{
    			case 'Q':
    				x = ReadInt();
    				y = ReadInt();
    				if (x > y) swap(x, y);
    				l = 0;
    				r = len - y + 1;
    				while (l < r)
    				{
    					mid = l + r + 1 >> 1;
    					if (Query(x, x + mid - 1) != Query(y, y + mid - 1)) r = mid - 1;
    					else l = mid;
    				}
    				printf("%d
    ", r);
    				break;
    			case 'R':
    				x = ReadInt();
    				d = ReadChar();
    				Modify(x, d - 'a' + 1);
    				break;		
    			case 'I':
    				x = ReadInt();
    				d = ReadChar();
    				Insert(x, d - 'a' + 1);
    				break;
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue 项目编译打包
    【Vue】基于nodejs的vue项目打包编译部署
    关于数据库设计中的状态字段
    Node.js安装及环境配置之Windows篇
    REST的本质,就是用户操作某个网络资源(具有独一无二的识别符URI),获得某种服务,也就是动词+资源(都是HTTP协议的一部分)
    微软重生:4年市值U型大逆转,超越谷歌重返巅峰!
    我在世界最热创业孵化器YC学到的58件事
    创业是否只是年轻人的专利?
    让你更值钱的方法:培养稀缺(追逐新技术,淬炼已有技能、做到出类拔萃,寻找自己所在的行业痛点,App开发者是市场动态平衡的典型)
    算法题
  • 原文地址:https://www.cnblogs.com/kcn999/p/13473417.html
Copyright © 2011-2022 走看看