HDU 3487 Play with Chain 【Splay】

1-n的序列,有两种操作:

1,将一段区间翻转

2,将一段区间切下来放到剩余序列的第C个数后

采用延迟更新的方法维护区间的翻转,并维护一个size域。

添加一个最大点和一个最小点,防止出界

翻转时,将第L-1个点伸展到跟,再将第R+1个点伸展到L-1的右子树,这时R+1的左子树就是要翻转的区间,加上一个标记。

切区间时,跟翻转操作差不多,只是不加标记。然后找到C+1和C,将C伸展到根,C+1伸展到C的右子树,此时C+1的左子树就是要插入的位置。

其实我说了这么多并没有什么卵用。。。。最后还是得自己画图看才能懂。

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int N=3e5+111;
int data[N],num[N],t[N][2],id,fa[N];
int flip[N],root,f;
inline void pushup(int x){
    num[x]=num[t[x][0]]+num[t[x][1]]+1;
}
inline void pushdown(int x){
    if(flip[x]){
        flip[x]=0;
        flip[t[x][0]]^=1;
        flip[t[x][1]]^=1;
        swap(t[x][0],t[x][1]);
    }
}
inline void Rotate(int x,int w){
    int y=fa[x];
    int z=fa[y];
    pushdown(y);
    t[y][!w]=t[x][w];
    fa[t[x][w]]=y;
    t[z][t[z][1]==y]=x;
    fa[x]=z;
    t[x][w]=y;
    fa[y]=x;
    pushup(y);
}
void newnode(int &x,int y,int v){
    x=++id;
    t[x][0]=t[x][1]=0;
    fa[x]=y;
    data[x]=v,flip[x]=0;
    num[x]=1;
}
void build(int &x,int y,int l,int r){
    if(l<=r){
        int mid=(l+r)>>1;
        newnode(x,y,mid);
        build(t[x][0],x,l,mid-1);
        build(t[x][1],x,mid+1,r);
        pushup(x);
    }
}
void init(int n){
    f=id=root=0;
    t[0][0]=t[0][1]=num[0]=data[0]=flip[0]=fa[0]=0;
    newnode(root,0,-1);
    newnode(t[1][1],root,-1);
    build(t[t[1][1]][0],t[1][1],1,n);
    pushup(t[1][1]);
    pushup(1);
}
void Splay(int x,int y){
    if(x!=y){
        pushdown(x);
        while(fa[x]!=y){
            if(t[fa[x]][0]==x)
                Rotate(x,1);
            else
                Rotate(x,0);
        }
        pushup(x);
        if(!y)root=x;
    }
}
int Kth(int k){
    int x=root;
    pushdown(root);
    for(;num[t[x][0]]+1!=k;){
        if(num[t[x][0]]+1>k)
            x=t[x][0];
        else
            k-=num[t[x][0]]+1,x=t[x][1];
        pushdown(x);
    }
    return x;
}
void Flip(int a,int b){
    a=Kth(a);
    b=Kth(b+2);
    Splay(a,0);
    Splay(b,a);
    flip[t[b][0]]^=1;
}
void Cut(int a,int b,int c){
    int tmp,d;

    a=Kth(a);b=Kth(b+2);
    Splay(a,0);Splay(b,a);
    tmp=t[b][0];t[b][0]=0;
    pushup(b);pushup(a);

    d=Kth(c+2);c=Kth(c+1);
    Splay(c,0);Splay(d,c);
    t[d][0]=tmp;fa[tmp]=d;
    pushup(d);pushup(c);
}
void Inorder(int x){
    if(x){
        pushdown(x);
        Inorder(t[x][0]);
        if(data[x]>0){
            if(f)
                putchar(‘ ‘);
            else    f=1;
            printf("%d",data[x]);
        }
        Inorder(t[x][1]);
    }
}
int main(){
    int n,m;
    char op[9];
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==-1)break;
        init(n);
        int a,b,c;
        while(m--){
            scanf("%s",op);
            if(op[0]==‘F‘){
                scanf("%d%d",&a,&b);
                Flip(a,b);
            }else{
                scanf("%d%d%d",&a,&b,&c);
                Cut(a,b,c);
            }
        }
        Inorder(root);
        puts("");
    }
    return 0;
}
时间: 2024-08-01 22:47:19

HDU 3487 Play with Chain 【Splay】的相关文章

hdu 3487 Play with Chain(splay区间剪切,翻转)

题目链接:hdu 3487 Play with Chain 题意: cut a b c: 将a到b区间剪切下来,放在第c位置的后面. flip a b: 翻转a到b区间 题解: 第一个操作,选通过旋转,然后使a到b区间变成根的右儿子的左儿子,然后剪掉. 再找到c+1的位置,接上. 第二个操作,区间标记就行. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4

HDU 4965 Fast Matrix Calculation 【矩阵】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4965 题目大意:给你一个N*K的矩阵A以及一个K*N的矩阵B (4 <= N <= 1000)以及 (2 <=K <= 6),然后接下来四步: 算一个新的矩阵C=A*B 算M=C^ (N*N) 对于M中的每个元素%6 将M中每个元素加起来,算出和. 也就是求出A*B * A*B * A*B * A*B * A*B *--* A*B   但是A*B形成的矩阵是N*N,而N大小有可能是10

hdu 5371 Hotaru&#39;s problem【manacher】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5371 题意: 给出一个长度为n的串,要求找出一条最长连续子串.这个子串要满足:1:可以平均分成三段,2:第一段和第三段相等,3:第一段和第二段回文.求最大子串的长度. 代码: #include<stdio.h> #include<iostream> #include<math.h> #include<stdlib.h> #include<ctype.h&

hdu 5352 MZL&#39;s City 【二分图】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352 题意: 给你n,m,k 表示n个建筑 m次操作,修复操作每次最多修复k个建筑. 有三种操作 1.修复x点周围建筑(<=k) 2.x,y建筑间建边 3.x,y间删边 修复建筑时候拆点建图.反着求最大匹配,保证字典序最小. 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <l

HDU 4923 Room and Moor【栈】【想法】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4923 题目大意:给你一串A = {A1, A2,..., AN}由{0,1}组成, 你要构造出一字符串 B = {B1, B2,... , BN}与A的长度相同. 求出这个最小值. 最开始见到这个题目先是想了想应该怎么做,比如先把A串处理一下. 1)把A前面的0去掉 2)把A后面的1去掉 3)将每部分的特值算出来. 举个栗子吧,字符串A将前的0去掉,后面的1去掉之后,字符串可以简化为N个 {1..

hdu 3487 Play with Chain (Splay)

hdu 3487 Splay树模板题 题意: 一开始给出1 2 3 4 ... n 这样一个序列,对这个序列进行以下两种操作: (1)CUT a b c: 将子串[a,b]切下来,放到剩余串的第c个数之后 . (2) FLIP a b : 将子串[a,b]翻转,如 1 2 3 4 就变成 4 3 2 1 . 总之就是一道Splay树的模板题 ... 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm&

hdu 3487 Play with Chain

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487 YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.He will perform t

HDU 5969 最大的位或 【贪心】 (2016年中国大学生程序设计竞赛(合肥))

最大的位或 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description B君和G君聊天的时候想到了如下的问题.给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大.其中|表示按位或,即C. C++. Java中的|运算. Input 包含至多10001组测试数据.第一行有一个正整数,表示数据的组数.接下

HDU 5968 异或密码 【模拟】 2016年中国大学生程序设计竞赛(合肥)

异或密码 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description 晨晨在纸上写了一个长度为N的非负整数序列{ai}.对于这个序列的一个连续子序列{al,al+1,-,ar}晨晨可以求出其中所有数异或的结果 alxoral+1xor...xorar其 中xor表示位异或运算,对应C.C++. Java等语言中的^运算.小璐提出了M个询问,每个询问用