题解 P1703 【那个什么密码2】
这应该是平衡树维护区间翻转的模板题吧
对于一次翻转(L , R)
主流的做法是Splay把编号为L-1的节点旋转到根
再把编号为R+1的节点旋转到根的右节点
这样根的右节点的左子树全为L---R,打上翻转标记即可
顺便再拓展一种算法,也就是我写的非选择treap
核心操作是split和merge
split是从某一位置把平衡树拆开,返回两个值即两根
merge是合并两个子树,要求保证某一子树元素严格小于另一子树
这样翻转区间L---R的时候
可以通过split拆出树1---L-1,树L---R,树R+1---n(均为编号)
在第二棵树的根上打上翻转标记
按顺序合并三棵树,在合并过程中下放标记
即可以复杂度O(len*log(len))的复杂度水过此题
以下是我的代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#define rt register int
#define ll long long
#define r read()
using namespace std;
inline int read()
{
int x = 0; int zf = 1; char ch;
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
int i,j,m,n,x,y,z,cnt,all,num,Root;
struct points{
int ls,rs,val,size,lazy;
}a[10010];
struct two{int ls,rs;};
inline void up(const int x)
{
a[x].size=a[a[x].ls].size+a[a[x].rs].size+1;
}
inline void down(const int x)
{
if(!a[x].lazy)return;
swap(a[x].ls,a[x].rs);
a[a[x].ls].lazy^=1;
a[a[x].rs].lazy^=1;
a[x].lazy=0;
}
inline int merge(const int x,const int y)//x < y
{
if(!x)return y;if(!y)return x;
down(x);down(y);
if(a[x].val>a[y].val)
{
a[y].ls=merge(x,a[y].ls);
up(y);
return y;
}
else
{
a[x].rs=merge(a[x].rs,y);
up(x);
return x;
}
}
two split(const int x,const int val)//rank 1...val ;val+1...n
{
two ret={0,0};down(x);
if(!x)return ret;rt p=a[a[x].ls].size+1;
if(p<=val)
{
ret=split(a[x].rs,val-p);
a[x].rs=ret.ls;
ret.ls=x;
}
else
{
ret=split(a[x].ls,val);
a[x].ls=ret.rs;
ret.rs=x;
}up(x);
return ret;
}
char v[10010],k,c[10010];short len1,len2;
void writes(const int x)
{
down(x);
if(a[x].ls)writes(a[x].ls);
putchar(c[x]);
if(a[x].rs)writes(a[x].rs);
}
inline int newnode(const int x)
{
cnt++;a[cnt].size=1;a[cnt].val=rand();return cnt;
}
inline void insert(const int val)
{
two u=split(Root,val);
Root=merge(merge(u.ls,u.rs),newnode(val));
}
inline void solve(const int L,const int R)
{
two p1=split(Root,L-1);
two p2=split(p1.rs,R-a[p1.ls].size);
a[p2.ls].lazy^=1;
Root=merge(p1.ls,merge(p2.ls,p2.rs));
}
int main()
{
srand(time(0));j=0;
scanf("%s %s",v+1,c+1);rt len1=strlen(v+1);n=strlen(c+1);
for(rt i=1,j=1;i<=n;i++,j++)
{
if(j>len1)j-=len1;
if(v[j]<='Z')k=v[j]-'A';else k=v[j]-'a';
if(c[i]<='Z')k+=c[i]-'A';else k+=c[i]-'a';
if(k>=26)k-=26;
if(c[i]<='Z')c[i]='A'+k;else c[i]='a'+k;
}
for(rt i=1;i<=n;i++)insert(i);
for(m=r;m;m--)
{
x=r;y=r;
solve(x,y);
}
writes(Root);
return 0;
}