牛客网多校第3场 C-shuffle card 【splay伸展树】

题目链接:戳这里

转自:戳这里

关于splay入门:戳这里

题意:给n个数,进行m次操作,每次都从n个数中取出连续的数放在最前面。

解题思路:splay的区间操作。

附代码:

 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 int n,m,sz,rt;
 5 int fa[100005],c[100005][2],id[100005];
 6 int size[100005];
 7 bool rev[100005];
 8 void pushup(int k)
 9 {
10     int l=c[k][0],r=c[k][1];
11     size[k]=size[l]+size[r]+1;
12 }
13 void pushdown(int k)
14 {
15     int l=c[k][0],r=c[k][1];
16     if(rev[k])
17     {
18         swap(c[k][0],c[k][1]);
19         rev[l]^=1;rev[r]^=1;
20         rev[k]=0;
21     }
22 }
23 void rotate(int x,int &k)
24 {
25     int y=fa[x],z=fa[y],l,r;
26     if(c[y][0]==x)l=0;else l=1;r=l^1;
27     if(y==k)k=x;
28     else {if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
29     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
30     c[y][l]=c[x][r];c[x][r]=y;
31     pushup(y);pushup(x);
32 }
33 void splay(int x,int &k)
34 {
35     while(x!=k)
36     {
37         int y=fa[x],z=fa[y];
38         if(y!=k)
39         {
40             if(c[y][0]==x^c[z][0]==y)rotate(x,k);
41             else rotate(y,k);
42         }
43         rotate(x,k);
44     }
45 }
46 int find(int k,int rank)
47 {
48     pushdown(k);
49     int l=c[k][0],r=c[k][1];
50     if(size[l]+1==rank)return k;
51     else if(size[l]>=rank)return find(l,rank);
52     else return find(r,rank-size[l]-1);
53 }
54 void rever(int l,int r)
55 {
56     int x=find(rt,l),y=find(rt,r+2);
57     splay(x,rt);splay(y,c[x][1]);
58     int z=c[y][0];
59     rev[z]^=1;
60 }
61 void build(int l,int r,int f)
62 {
63     if(l>r)return;
64     int now=id[l],last=id[f];
65     if(l==r)
66     {
67         fa[now]=last;size[now]=1;
68         if(l<f)c[last][0]=now;
69         else c[last][1]=now;
70         return;
71     }
72     int mid=(l+r)>>1;now=id[mid];
73     build(l,mid-1,mid);build(mid+1,r,mid);
74     fa[now]=last;pushup(mid);
75     if(mid<f)c[last][0]=now;
76     else c[last][1]=now;
77 }
78 int main()
79 {
80     scanf("%d%d",&n,&m);
81     for(int i=1;i<=n+2;i++)
82         id[i]=++sz;
83     build(1,n+2,0);rt=(n+3)>>1;
84     for(int i=1;i<=m;i++)
85     {
86         int l,r;
87         scanf("%d%d",&l,&r);
88         rever(1,l+r-1); //区间通过3次翻转,达到洗牌效果
89         rever(1,r);
90         rever(r+1,l+r-1);
91     }
92     for(int i=2;i<=n+1;i++)
93         printf("%d ",find(rt,i)-1);
94     return 0;
95 }
View Code

猜你喜欢

转载自www.cnblogs.com/zmin/p/9402729.html