bzoj5063 旅游

(http://www.elijahqi.win/2018/01/23/bzoj5063-%E6%97%85%E6%B8%B8/%20%E2%80%8E)
Description
小奇成功打开了大科学家的电脑。
大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序。初
始时,序列为1,2,…,n。
接着,大科学家进行m次操作来打乱顺序。每次操作有6步:
1、从序列开头(左端)取出A个数(此时序列剩下n-A个数)
2、从序列开头取出B个数
3、将第1步取出的A个数按原顺序放回序列开头
4、从序列开头取出C个数
5、将第2步取出的B个数逆序放回序列开头
6、将第4步取出的C个数按原顺序放回序列开头
你需要求出最终序列。
Input
第一行两个数n,m。接下来m行,每行三个数A,B,C。
n,m<=100000
Output
输出一行n个数表示最终序列。
Sample Input
10 2
6 2 2
5 3 6
Sample Output
1 2 8 7 3 9 6 5 4 10
这题卡常..
我试着卡了卡常数还差一点就T了 说明蒟蒻我好菜呀
拿到题目算一算数据范围 常数大的我直接T飞了 那怎么搞 再看一看题目的要求推导一下题目要求的操作 发现哦原来可以化简成两个操作 1、把a+1~a+b一段取出来 反转 然后在把序列在c后面拆开 重新把反转后的放入 即可 搜了搜题解:发现?结构体比数组快一倍?orzqwq我好菜呀

#include<cstdio>
#include<algorithm>
#define N 110000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0;char ch=gc();
    while(ch<'0'||ch>'9') ch=gc();
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x;
}
int c[N][2],size[N],fa[N],v[N],rev[N],n,m,root;
inline void update(int x){
    size[x]=size[c[x][0]]+size[c[x][1]]+1;
}
inline void build(int f,int l,int r){
    if (l>r) return;
    int mid=l+r>>1;c[f][mid>f]=mid;fa[mid]=f;v[mid]=mid-1;
    if (l==r){size[l]=1;return;}
    build(mid,l,mid-1);build(mid,mid+1,r);update(mid);
}
inline void pushdown(int x){
    if (!rev[x]) return;
    int l=c[x][0],r=c[x][1];
    rev[l]^=1;rev[r]^=1;rev[x]=0;
    swap(c[l][0],c[l][1]);swap(c[r][0],c[r][1]);
}
inline int find(int x,int sz){
    pushdown(x);int l=c[x][0],r=c[x][1];
    if (size[l]+1==sz) return x;
    if (sz<=size[l]) return find(l,sz);else return find(r,sz-size[l]-1);
}
inline void rotate(int x,int &tar){
    int y=fa[x],z=fa[y];
    if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
    int l=c[y][1]==x,r=l^1;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
    while(x!=tar){
        int y=fa[x],z=fa[y];
        if (y!=tar){
            if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
        }rotate(x,tar);
    }
}
inline int split(int x,int y){
    int xx=find(root,x),yy=find(root,y);
    splay(yy,root);splay(xx,c[root][0]);return c[xx][1];
}
inline void print(int x){
    pushdown(x);if (c[x][0]) print(c[x][0]);
    if (v[x]!=0&&v[x]!=n+1)printf("%d ",v[x]);
    if (c[x][1]) print(c[x][1]);
}
int main(){
    freopen("bzoj5063.in","r",stdin);
    n=read();m=read();build(0,1,n+2);root=n+3>>1;
    for (int i=1;i<=m;++i){
        int a=read(),b=read(),cc=read();
        int tmp=split(a+1,a+b+2),f=fa[tmp];c[f][1]=0;update(f);update(fa[f]);
        int xx=find(root,cc+1),yy=find(root,cc+2);splay(yy,root);splay(xx,c[root][0]);
        rev[tmp]^=1;swap(c[tmp][0],c[tmp][1]);c[xx][1]=tmp;fa[tmp]=xx;update(xx);update(root);
    }print(root);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值