题目链接
题意:
有一堆卡牌,一开始是从1到n的序列放好,现在有M次操作。每次操作将从第Pi个卡牌开始往后拿出Si个卡牌放在剩余卡牌的上方。问最后序列是什么。
思路:
打完比赛的时候发现了大佬的解法,用了一个完全没听过的操作rope。代码几乎可以说是和string一样了,但是它的速度却是惊人的快,赶紧学起来!!!
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
rope<int> a;
int main()
{
int n,q,l,r;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
a+=i;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
a=a.substr(l-1,r)+a.substr(0,l-1)+a.substr(l+r-1,n-(l+r-1)+1);
}
for(int i=0;i<n;i++)
{
if(i!=n-1)
printf("%d ",a[i]);
else
printf("%d\n",a[i]);
}
return 0;
}
正常的思路:
用一个平衡树来处理,这个操作,先将1~Pi+Si-1这个区间翻转。然后再将1~Si区间翻转,和Si+1~Pi+Si-1区间翻转就是最后的区间。这里学了一下fhqtreap,一个非旋转的treap代码比SPLAY好写很多。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
using namespace std;
const int maxn=1e5+5;
struct node
{
int son[2],v,rnd,size;
int fz;
}tr[maxn];
int n,m,l,r;
int tot,root;
int new_node(int v)//创建权值为v的结点。
{
tot++;
tr[tot].size=1;
tr[tot].v=v;
tr[tot].rnd=rand();
tr[tot].fz=tr[tot].son[0]=tr[tot].son[1]=0;
return tot;
}
void update(int x)
{
tr[x].size=tr[tr[x].son[0]].size+tr[tr[x].son[1]].size+1;
if(x&&tr[x].fz)
{
tr[tr[x].son[0]].fz^=1;
tr[tr[x].son[1]].fz^=1;
swap(tr[x].son[0],tr[x].son[1]);
tr[x].fz^=1;
}
}
int build(int l,int r)
{
if(l>r) return 0;
int mid=(l+r)/2;
int v=mid-1;
int now=new_node(v);
tr[now].son[0]=build(l,mid-1);
tr[now].son[1]=build(mid+1,r);
update(now);
return now;
}
int merge(int x,int y)
{
if(!x||!y)
return x+y;
update(x),update(y);
if(tr[x].rnd<tr[y].rnd)
{
tr[x].son[1]=merge(tr[x].son[1],y);
update(x);
return x;
}
else
{
tr[y].son[0]=merge(x,tr[y].son[0]);
update(y);
return y;
}
}
void split(int now,int k,int &x,int &y)//按照节点个数分离,把节点个数小于k的分给x,大于等于的分给y
{
if(!now)
x=y=0;
else
{
update(now);
if(k<=tr[tr[now].son[0]].size)
y=now,split(tr[now].son[0],k,x,tr[now].son[0]);
else
x=now,split(tr[now].son[1],k-tr[tr[now].son[0]].size-1,tr[now].son[1],y);
update(now);
}
}
void rev(int l,int r)
{
int x,y,u,v;
split(root,r+1,x,y);
split(x,l,u,v);
tr[v].fz^=1;
root=merge(merge(u,v),y);
}
void print(int now)
{
if(!now)
return;
update(now);
print(tr[now].son[0]);
if(tr[now].v>=1&&tr[now].v<=n)
printf("%d ",tr[now].v);
print(tr[now].son[1]);
}
int main()
{
srand((unsigned)time(NULL));
scanf("%d%d",&n,&m);
root=build(1,n+2);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
rev(1,l+r-1);
rev(1,r);
rev(r+1,l+r-1);
}
print(root);
return 0;
}