【BZOJ 1014】 [JSOI2008]火星人prefix
【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1014
【题意】 
 
让你在线查询最长公共前缀. 
支持单节点修改; 
插入操作;
【题解】
/*
    伸展树会保证
    这棵树的中序遍历的结果是s[1..n]
    即整个序列;
    在进行旋转操作的时候,这个性质能被保持住;
    伸展树在维护的时候;
    每次会把需要操作的节点转到根节点;
    然后进行对应的操作;
    我们在进行
    LCQ(x,y)的时候,
    先二分枚举长度len;
    然后把
    x-1,x+len的节点编号获取a1,a2;
    y-1,y+len的节点编号也获取b1,b2;
    然后把a1转到根节点,a2放到根节点(也就是a1)的下面;
    因为x+len>x-1所以a2肯定是在a1的右儿子处;
    而这个时候a2的左子树代表的字符就是
    s[x..x+len-1]了;
    相应的对b1,b2也做同样的事情
    也能获取s[y..y+len-1];
    根据伸展树维护的hash值判断这两个子串是否相同。。
    如果相同的话,就可以让len边长一点;
    不同的话,肯定不能变长了,就变短一点呗.
    然后返回答案就好
    插入操作的话;
    先提取x节点,把它转到根节点的位置;
    然后再提取x+1号节点,把它转到根节点的下方
    这里x+1号节点的左儿子肯定是空的,因为x和x+1是连在一起的;
    中间不可能还有比x+1小的了;
    则把这个新插入的节点放在x+1号节点的左边.
    修改操作就简答多了
    直接找到那个节点;
    然后把它转到根节点去;
    再修改它的值;
    这里记住每次都把节点转到根节点就好
    头部和尾部都要加一个空节点;
    这样做写插入操作会好写一点吧?
    hash值可以搜一下RKhash;
    这里不用管它会溢出;
    你开一个unsigned long long就可以毁天灭地了;
    let it go~~
*/【完整代码】
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL unsigned long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define which(x) (ch[fa[x]][1]==x)
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 1e5 + 200;
const LL seed = 131;
char s[N], str[N], op[10], val[10];
int m, n, fa[N], tot, ch[N][2], root, x, siz[N];
LL po_w[N], has[N];
void push_up(int x)
{
    siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
    has[x] = has[ch[x][0]] + po_w[siz[ch[x][0]]] * str[x] + po_w[siz[ch[x][0]] + 1] * has[ch[x][1]];
}
int build(int l, int r, int rt)
{
    if (l > r) return 0;
    int mid = (l + r) >> 1;
    int x = ++tot;
    fa[x] = rt; str[x] = s[mid];
    ch[x][0] = build(l, mid - 1, x);
    ch[x][1] = build(mid + 1, r, x);
    push_up(x);
    return x;
}
int Rank(int x, int k)
{
    if (siz[ch[x][0]] >= k)
        return Rank(ch[x][0], k);
    else
        if (k == siz[ch[x][0]] + 1)
            return x;
        else
            return Rank(ch[x][1], k - siz[ch[x][0]] - 1);
}
void Rotate(int x)
{
    int f = fa[x];
    bool k = which(x);
    ch[f][k] = ch[x][!k];
    ch[x][!k] = f;
    ch[fa[f]][which(f)] = x;
    fa[ch[f][k]] = f;
    fa[x] = fa[f];
    fa[f] = x;
    siz[x] = siz[f], has[x] = has[f];
    push_up(f);
}
void Splay(int x, int g)
{
    while (fa[x] != g)
    {
        int f = fa[x];
        if (fa[f] == g)
        {
            Rotate(x);
            break;
        }
        if (which(x) ^ which(f))
            Rotate(x);
        else
            Rotate(f);
        Rotate(x);
    }
    if (!g) root = x;
}
void Change(int pos, char val)
{
    int x = Rank(root, pos);
    Splay(x, 0);
    str[x] = val;
    push_up(x);
}
void Insert(int pos, char val)
{
    int x = Rank(root, pos), y = Rank(root, pos + 1);
    Splay(x, 0), Splay(y, x);
    ch[y][0] = ++tot;
    str[tot] = val, fa[tot] = y;
    push_up(tot), push_up(y), push_up(x);
}
int lcq(int tx, int ty)
{
    int l = 0, r = n, ans = 0;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (ty + mid - 1 > n + 1) //?????
        {
            r = mid - 1;
            continue;
        }
        //[tx..tx+mid-1] but (tx-1,tx+mid)
        int x = Rank(root, tx - 1), y = Rank(root, tx + mid);
        Splay(x, 0), Splay(y, x);
        LL temp1 = has[ch[y][0]];
        x = Rank(root, ty - 1), y = Rank(root, ty + mid);
        Splay(x, 0), Splay(y, x);
        if (temp1 == has[ch[y][0]])
        {
            ans = mid;
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
    return ans;
}
int main()
{
    //freopen("F:\\rush.txt", "r", stdin);
    po_w[0] = 1;
    rep1(i, 1, N - 2)
        po_w[i] = po_w[i - 1] * seed;
    scanf("%s", s + 1);
    n = strlen(s + 1);
    root = build(0, n + 1, 0);
    rei(m);
    rep1(i, 1, m)
    {
        scanf("%s", op);
        if (op[0] == 'R')
        {
            scanf("%d%s", &x, val);
            Change(x + 1, val[0]);
        }
        else
            if (op[0] == 'I')
            {
                scanf("%d%s", &x, val);
                Insert(x + 1, val[0]);
                n++;
            }
            else
                if (op[0] == 'Q')
                {
                    int x, y;
                    scanf("%d%d", &x, &y);
                    if (x > y)
                        swap(x, y);
                    if (x != y)
                        printf("%d\n", lcq(x + 1, y + 1));
                    else
                        printf("%d\n", n - x + 1);
                }
    }
    return 0;
}【BZOJ 1014】 [JSOI2008]火星人prefix的更多相关文章
- BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash]  【未完】
		1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6243 Solved: 2007[Submit] ... 
- BZOJ 1014: [JSOI2008]火星人prefix Splay+二分
		1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ... 
- bzoj 1014: [JSOI2008]火星人prefix hash && splay
		1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3154 Solved: 948[Submit][ ... 
- 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix
		1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4164 Solved: 1277[Submit] ... 
- BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
		用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ... 
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
		1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8112 Solved: 2569[Submit] ... 
- [BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】
		题目链接:BZOJ - 1014 题目分析 求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等. 这里有修改 ... 
- BZOJ 1014: [JSOI2008]火星人prefix
		Sol Splay+Hash+二分答案. 用Splay维护Hash,二分答案判断. 复杂度 \(O(nlog^2n)\) PS:这题调了两个晚上因为没开long long.许久不写数据结构题感觉写完整 ... 
- bzoj 1014 [JSOI2008]火星人prefix(splay+hash)
		[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1014 [题意] 给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP ... 
- bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
		题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用splay维护字符串,每个点记录子树的哈希值,然后二分查询. 二分不是把两个点的哈希 ... 
随机推荐
- Android Material风格的应用(五)--CollapsingToolbar
			Collapsing Toolbar Android Material风格的应用(一)--AppBar TabLayoutAndroid Material风格的应用(二)--RecyclerViewA ... 
- php课程 11-37 类和对象的关系是什么
			php课程 11-37 类和对象的关系是什么 一.总结 一句话总结:类生成对象,对象是类的实例化,一定是先有类,后有对象,一定是先有标准,再有个体. 1.oop的三大优势是什么? 重用性,灵活性.扩展 ... 
- linux终端下一些“风骚”的按键操作及Linux终端命令
			linux终端下一些"风骚"的按键操作 <backspace> 删除 <ctrl-l> 清空屏幕, 相当于clear tab ... 
- 使用wepy开发微信小程序商城第三篇:购物车(布局篇)
			使用wepy开发微信小程序商城 第三篇:购物车(布局篇) 前两篇如下: 使用wepy开发微信小程序商城第一篇:项目初始化 使用wepy开发微信小程序商城第二篇:路由配置和页面结构 基于上两篇内容,开始 ... 
- 全端project师必备技能汇总
			首先,看一张前端知识结构图: (原文: ithomer) 图片的形式具有诸多的不便.缺失源图的我们.无法为此图贡献些什么,随着时间的迁移,也许有些技术点会发生改变.所以有了这个GitHub项目.我们 ... 
- linux的几个内核镜像格式Image 和 u-boot启动内核和文件系统时的一些环境变量的设置
			关于编译powerpc linux的几个Image参考原文 http://blog.sina.com.cn/s/blog_86a30b0c0100wfzt.html 转载▼ PowerPC架构 L ... 
- UVALive - 4960 Sensor network(生成树+LCA)
			题目大意:给出N个点.M条边.问这N个点形成的生成树的最大权值边-最小权值边的最小值 解题思路:先排序,然后按生成树的kruscal算法进行加边,再维护一个最小权值边 加边的时候要考虑一下加下去的边是 ... 
- hdu Minimum Transport Cost(按字典序输出路径)
			http://acm.hdu.edu.cn/showproblem.php? pid=1385 求最短路.要求输出字典序最小的路径. spfa:拿一个pre[]记录前驱,不同的是在松弛的时候.要考虑和 ... 
- java用volatile或AtomicBoolean实现高效并发处理 (只初始化一次的功能要求)
			最近碰到一个这样的功能要求:怎么在一个类里面,实现高效并发处理下只可以初始化一次的方法? 实现方式: 1)volatile方式: /** * Created by Chengrui on 2015/7 ... 
- jquery插件课程1  幻灯片、城市选择、日期时间选择、拖放、方向拖动插件
			jquery插件课程1 幻灯片.城市选择.日期时间选择.拖放.方向拖动插件 一.总结 一句话总结:都是jquery插件,都还比较小,参数(配置参数.数据)一般都是通过json传递. 1.插件配置数据 ... 
