[bzoj1014]:[JSOI2008]火星人prefix

2024-02-05 15:08

本文主要是介绍[bzoj1014]:[JSOI2008]火星人prefix,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门
这个题我一眼秒,然后发现好像是查询好像变成了 O(log2n)
然后发现数据范围说查询操作不超过10000次,然后就觉得应该是正解了。。
然后调试了超级久。。。
再然后就WA了3个点。。
最后发现我调试的时候为了方便,质数只取到了1000,然后取到1e9+7,就过了。。
我们来说正解吧。


emmmm,一句话题解吧。
Splay+Hash+二分
好像有点儿少,还是具体说说吧。。
首先,因为有插入操作,还有修改,还有查询,所以肯定要用Splay
具体用法的话可以参考NOI2005维修数列
然后还有字符串Hash,正常Hash就好了,出题人没有卡Hash。
(注意,这个题时间比较紧,不要取模,自然溢出就好了)
然后查询的时候,我们只要二分一个答案mid
然后判断[x,x+mid-1]和[y,y+mid-1]这两段的Hash值是否相同就好了
相同,则l=mid
不相同,则r=mid-1
然后取mid的时候要这样取mid=(l+r+1)>>1
然后还要while(l < r)
最后返回l
不要问我怎么知道这么做的
(其实是试出来的)
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll unsigned long long
using namespace std;
inline int read(){int x=0;char ch=' ';int f=1;while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();if(ch=='-')f=-1,ch=getchar();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x*f;
}
const int N=2e5+5;
const ll p=1e9+7;
char cc[N];
int n,m,sz,root;
int f[N],ch[N][2];
ll fac[N],val[N],sum[N],size[N];
inline void pushup(int x){int lc=ch[x][0],rc=ch[x][1];sum[x]=sum[lc]*(fac[size[rc]+1])+sum[rc]+val[x]*fac[size[rc]];size[x]=size[lc]+size[rc]+1;
}
inline bool get(int x){return ch[f[x]][1]==x;}
inline void rotate(int x){int y=f[x],z=f[y],w=get(x),w2=get(y);ch[y][w]=ch[x][w^1];f[ch[y][w]]=y;ch[x][w^1]=y;f[y]=x;f[x]=z;if(z)ch[z][w2]=x;pushup(y);pushup(x);
}
inline void splay(int x,int goal){// cout<<"splay "<<x<<" to "<<goal<<endl;for(int fa=0;(fa=f[x])!=goal;rotate(x))if(f[fa]!=goal)rotate((get(fa)==get(x))?fa:x);if(!goal)root=x;// cout<<"   success!"<<endl;
}
inline void build(int &x,int l,int r,int fa){if(l>r){x=0;return;}int mid=(l+r)>>1;x=++sz;val[sz]=sum[sz]=cc[mid-1]-'a'+1;size[sz]=1;f[sz]=fa;if(mid==1)val[sz]=sum[sz]=0;if(mid==n+2)val[sz]=sum[sz]=0;if(!(l^r))return;build(ch[x][0],l,mid-1,x);build(ch[x][1],mid+1,r,x);pushup(x);
}
inline int kth(int k){int now=root;while(1){if(ch[now][0]&&k<=size[ch[now][0]])now=ch[now][0];else{int tmp=size[ch[now][0]]+1;if(k<=tmp){return now;}k-=tmp;now=ch[now][1];}}
}
inline void print(int);
inline int split(int L,int R){if(L>R)return 0;L++;R++;// cout<<"split "<<L-1<<' '<<R-1<<endl;int l=kth(L-1);splay(l,0);int r=kth(R+1);splay(r,l);// cout<<l<<' '<<r<<endl;// cout<<"   success!"<<endl;// print(root);return ch[r][0];
}
inline ll query(int L,int R){int now=split(L,R);return sum[now];
}
inline void insert(int pos,char c){n++;int now=split(pos,pos);val[++sz]=sum[sz]=c-'a'+1;size[sz]=1;f[sz]=now;ch[now][1]=sz;pushup(now);pushup(ch[root][1]);pushup(root);// print(root);
}
inline void change(int pos,char c){int now=split(pos,pos);val[now]=sum[now]=c-'a'+1;size[now]=1;pushup(ch[root][1]);pushup(root);
}
inline int find(int x,int y){if(x>y)swap(x,y);ll pre1=query(x,x);ll pre2=query(y,y);if(pre1!=pre2)return 0;int l=1,r=n-y+1,mid;while(l<r){// cout<<"find "<<l<<' '<<r<<endl;mid=(l+r+1)>>1;ll v1=query(x,x+mid-1);// cout<<v1<<' ';ll v2=query(y,y+mid-1);// cout<<v2<<endl;if(v1==v2)l=mid;else r=mid-1;// system("pause");}return l;
}
inline void print(int now){cout<<endl;cout<<"id:  "<<now<<endl;cout<<"val: "<<val[now]<<endl;cout<<"sum: "<<sum[now]<<endl;cout<<"fa:  "<<f[now]<<endl;cout<<"lc:  "<<ch[now][0]<<endl;cout<<"rc:  "<<ch[now][1]<<endl;cout<<endl;// system("pause");if(ch[now][0])print(ch[now][0]);if(ch[now][1])print(ch[now][1]);
}
int main(){scanf("%s",cc+1);m=read();n=strlen(cc+1);fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*p;build(root,1,n+2,0);sz=n+2;// print(root);while(m--){int x,y;char opt[3],c[3];scanf("%s",opt);if(opt[0]=='Q')x=read(),y=read(),printf("%d\n",find(x,y));if(opt[0]=='R')x=read(),scanf("%s",c),change(x,c[0]);if(opt[0]=='I')x=read(),scanf("%s",c),insert(x,c[0]);}return 0;
}

这篇关于[bzoj1014]:[JSOI2008]火星人prefix的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681300

相关文章

USACO Section 2.3 Longest Prefix

题意: 给你一大堆小字符串  和  一个大字符串  求  使用小字符串能拼出的大字符串的前缀最长是多少 思路: 由于数据不大  所以可以尝试扫描大字符串  每到一个位置用小字符串拼一下看看能拼多长  拼的最远距离就是答案 我用trie树来存小字符串集合  扫描大字符串时  如果该位置是可以向后延伸的(即之前能拼到这个位置) 那么我用一个标记在trie树上爬  每次发现一个小字符串结

CodeForces 487C Prefix Product Sequence

题意: 构造一个1~n的排列  使得n个前缀积%n是一个0~n-1的排列 思路: 首先确定n一定放最后  要不然会有%n会有多个0  这时n-1位置的前缀积为(n-1)! 接着讨论n  n为合数时只有n=4有解  因为如果n为合数一定可以拆成p*q的形式  明显pq|(n-1)! 然后构造ai=(i+1)*inv[i]  因为(i+1)*inv[i] == (j+1)*inv[j]时一

Prefix Sum 总结

注意:prefixsum一般都是用PrefixSum[n+1]的数组,prefix[0] = 0; 那么 因为i, j 是A里面的坐标,而prefixsum比A多了1;所以原来的sum[j] - sum[i-1]变成了 sum(i~j) = prefixsum(j + 1) - prefixsum(i); Interval Sum 思路:因为这个题目不需要modify数组操作

leetcode --- Longest Common Prefix

最长公共前缀(Longest  Common  Prefix) 题目:Write a function to find the longest common prefix string amongst an array of strings. 题目链接:https://leetcode.com/problems/longest-common-pref

leetcode 刷题之路 8 Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 寻找一组字符串的最长公共前缀,比较简单,直接贴上程序: accepted answer: class Solution {public:string longestCommonPrefix(vector<str

Leetcode25: Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 求若干字符串的最长公共前缀。 首先若无字符串,返回“”;接下来求得其中最短字符串的长度len,比较公共前缀只需最多比较len次;最后比较所有字符串里每一位上的字符。 class Solution {public:s

Leetcode171: Implement Trie (Prefix Tree)

Implement a trie with insert, search, and startsWith methods. Trie树又被称为字典树、前缀树,是一种用于快速检索的多叉树。Tried树可以利用字符串的公共前缀来节省存储空间。 但如果系统存在大量没有公共前缀的字符串,相应的Trie树将非常消耗内存。 Trie树的基本性质如下: 根节点不包括字符,除根节点外每个节点包括

LeetCode | Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 求字符串最长公共前缀,这题也没啥好说的,就代码可读性上说一说好了。 我写的虽然也是4ms虽然也没错,但是可读性上来说相对差了一点 class Solution {public:string longestComm

(LeetCode)Longest Common Prefix --- 最长公共前缀

Write a function to find the longest common prefix string amongst an array of strings. Subscribe to see which companies asked this question 解题分析: 首先要理解,如果是空串的话,那么说明前

CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中

CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中 code review! 文章目录 CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中1.`CMAKE_INSTALL_PREFIX`详解变量作用设置 `CMAKE_INSTALL_PREFIX`示例影响范围常