2018牛客网暑期ACM多校训练营(第三场)C Shuffle Cards(可持久化平衡树/splay)
题意
牌面初始是1到n,进行m次洗牌,每次抽取一段放到最前面。求最后的序列。
分析
神操作!!!比赛时很绝望,splay技能尚未点亮,不知道怎么用。
殊不知,C++库里有rope神器,即块状链表。
基础函数
#include <ext/rope> using namespace __gnu_cxx; rope test; test.push_back(x);//在末尾添加x test.insert(pos,x);//在pos插入x test.erase(pos,x);//从pos开始删除x个 test.copy(pos,len,x);//从pos开始到pos+len为止用x代替 test.replace(pos,x);//从pos开始换成x test.substr(pos,x);//提取pos开始x个 test.at(x)/[x];//访问第x个元素
有了上面的函数,就解决这道题了(狗头。
#include<iostream> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<cstdio> #include<algorithm> #include<map> #include<set> #include<ext/rope> #define rep(i,e) for(int i=0;i<(e);i++) #define rep1(i,e) for(int i=1;i<=(e);i++) #define repx(i,x,e) for(int i=(x);i<=(e);i++) #define X first #define Y second #define PB push_back #define MP make_pair #define mset(var,val) memset(var,val,sizeof(var)) #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define pd(a) printf("%d\n",a) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define IOS ios::sync_with_stdio(false);cin.tie(0) #define lc idx<<1 #define rc idx<<1|1 #define rson mid+1,r,rc #define lson l,mid,lc using namespace std; typedef long long ll; int read() { int x = 0; char c = getchar(); while (c < '0' || c > '9')c = getchar(); while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x; } template <class T> void test(T a){cout<<a<<endl;} template <class T,class T2> void test(T a,T2 b){cout<<a<<" "<<b<<endl;} template <class T,class T2,class T3> void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;} const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; const ll mod = 1e9+7; int T; void testcase(){ printf("Case %d: ",++T); } const int MAXN = 1e5+10; const int MAXM = 30; const double eps = 1e-9; using namespace __gnu_cxx; int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL int n,m; n=read();m=read(); rope<int> ro; for(int i=1;i<=n;i++) ro.push_back(i); int x,y; while(m--){ x=read();y=read(); ro=ro.substr(x-1,y)+ro.substr(0,x-1)+ro.substr(y+x-1,n-x-y+1); } for(int i=0;i<n;i++){ printf("%d%c",ro[i],(i==n-1?'\n':' ')); } return 0; }
splay实现:区间交换可以用区间翻转来实现
如 1 2 3 4 5,将区间[2,4]移到前面.。
可用三次翻转实现
4 3 2 1 5 翻转[2,4]
2 3 4 1 5 翻转[1,3]
2 3 4 1 5 翻转[4,4]
这样套个模板,注意输出格式
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; #define Key_value ch[ch[root][1]][0] const int MAXN=500010; const int INF=0x3f3f3f3f; int pre[MAXN],ch[MAXN][2],key[MAXN],size[MAXN]; int sum[MAXN],rev[MAXN],same[MAXN]; int lx[MAXN],rx[MAXN],mx[MAXN]; int root,tot1; int s[MAXN],tot2; int a[MAXN]; int n,q; //debug部分 void Treavel(int x) { if(x) { Treavel(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d key=%2d, size= %2d, sum=%2d,rev=%2d same=%2d lx=%2d rx=%2d mx=%2d\n",x,ch[x][0],ch[x][1],pre[x],key[x],size[x],sum[x],rev[x],same[x],lx[x],rx[x],mx[x]); Treavel(ch[x][1]); } } void debug() { printf("root%d\n",root); Treavel(root); } void NewNode(int &r,int father,int k) { if(tot2)r=s[tot2--]; else r=++tot1; pre[r]=father; ch[r][0]=ch[r][1]=0; key[r]=k; sum[r]=k; rev[r]=same[r]=0; lx[r]=rx[r]=mx[r]=k; size[r]=1; } void Update_Same(int r,int v) { if(!r)return; key[r]=v; sum[r]=v*size[r]; lx[r]=rx[r]=mx[r]=max(v,v*size[r]); same[r]=1; } void Update_Rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); swap(lx[r],rx[r]); rev[r]^=1;//这里要注意,一定是异或1 } void Push_Up(int r) { int lson=ch[r][0],rson=ch[r][1]; size[r]=size[lson]+size[rson]+1; sum[r]=sum[lson]+sum[rson]+key[r]; lx[r]=max(lx[lson],sum[lson]+key[r]+max(0,lx[rson])); rx[r]=max(rx[rson],sum[rson]+key[r]+max(0,rx[lson])); mx[r]=max(0,rx[lson])+key[r]+max(0,lx[rson]); mx[r]=max(mx[r],max(mx[lson],mx[rson])); } void Push_Down(int r) { if(same[r]) { Update_Same(ch[r][0],key[r]); Update_Same(ch[r][1],key[r]); same[r]=0; } if(rev[r]) { Update_Rev(ch[r][0]); Update_Rev(ch[r][1]); rev[r]=0; } } void Build(int &x,int l,int r,int father) { if(l>r)return; int mid=(l+r)/2; NewNode(x,father,a[mid]); Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init() { root=tot1=tot2=0; ch[root][0]=ch[root][1]=pre[root]=size[root]=same[root]=rev[root]=sum[root]=key[root]=0; lx[root]=rx[root]=mx[root]=-INF; NewNode(root,0,-1); NewNode(ch[root][1],root,-1); for(int i=0;i<n;i++) a[i]=i+1; Build(Key_value,0,n-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void Rotate(int x,int kind) { int y=pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; Push_Up(y); } void Splay(int r,int goal) { Push_Down(r); while(pre[r]!=goal) { if(pre[pre[r]]==goal) { Push_Down(pre[r]); Push_Down(r); Rotate(r,ch[pre[r]][0]==r); } else { Push_Down(pre[pre[r]]); Push_Down(pre[r]); Push_Down(r); int y=pre[r]; int kind=ch[pre[y]][0]==y; if(ch[y][kind]==r) { Rotate(r,!kind); Rotate(r,kind); } else { Rotate(y,kind); Rotate(r,kind); } } } Push_Up(r); if(goal==0)root=r; } int Get_Kth(int r,int k) { Push_Down(r); int t=size[ch[r][0]]+1; if(t==k)return r; if(t>k)return Get_Kth(ch[r][0],k); else return Get_Kth(ch[r][1],k-t); } //在第pos个数后插入tot个数 void Insert(int pos,int tot) { for(int i=0;i<tot;i++)scanf("%d",&a[i]); Splay(Get_Kth(root,pos+1),0); Splay(Get_Kth(root,pos+2),root); Build(Key_value,0,tot-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void erase(int r) { if(!r)return; s[++tot2]=r; erase(ch[r][0]); erase(ch[r][1]); } //从第pos个数开始连续删除tot个数 void Delete(int pos,int tot) { Splay(Get_Kth(root,pos),0); Splay(Get_Kth(root,pos+tot+1),root); erase(Key_value); pre[Key_value]=0; Key_value=0; Push_Up(ch[root][1]); Push_Up(root); } //从第pos个数连续开始的tot个数修改为c void Make_Same(int pos,int tot,int c) { Splay(Get_Kth(root,pos),0); Splay(Get_Kth(root,pos+tot+1),root); Update_Same(Key_value,c); Push_Up(ch[root][1]); Push_Up(root); } //反转 void Reverse(int pos,int tot) { Splay(Get_Kth(root,pos),0); Splay(Get_Kth(root,pos+tot+1),root); Update_Rev(Key_value); Push_Up(ch[root][1]); Push_Up(root); } //求和 int Get_Sum(int pos,int tot) { Splay(Get_Kth(root,pos),0); Splay(Get_Kth(root,pos+tot+1),root); return sum[Key_value]; } //得到最大和 int Get_MaxSum(int pos,int tot) { Splay(Get_Kth(root,pos),0); Splay(Get_Kth(root,pos+tot+1),root); return mx[Key_value]; } int cnt; void Inorder(int r) { if(!r)return; Push_Down(r); Inorder(ch[r][0]); if(key[r]!=-1) printf("%d%c",key[r],++cnt==n?'\n':' '); Inorder(ch[r][1]); } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&q)==2) { Init(); int x,y; while(q--){ scanf("%d%d",&x,&y); Reverse(1,y+x-1); Reverse(1,y); Reverse(y+1,x-1); } cnt=0; Inorder(root); } return 0; }