UVA 11922(Splay

题目:维护一个序列,支持将一段数翻转并插到最后的操作,最后输出整个序列。

思路:直接套的大白模板,第一次用splay,贴一下。。

/*
*@author:  Cwind
*http://www.cnblogs.com/Cw-trip/
*/
#include <bits/stdc++.h>
#define pb push_back
#define PB pop_back
#define bk back()
#define se second
#define fs first
#define IINF (1<<29)
#define sq(x) (x)*(x)
#define eps 0.000000001
#define clr(x) memset((x),0,sizeof (x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;

const int maxp=1e6+3000;
struct Node{
    int s;
    int val;
    bool flip;
    Node *ch[2];
    Node():s(0),flip(0){}
    int cmp(const int k)const {
        int d=k-ch[0]->s;
        if(d==1) return -1;
        else return d>0;
    }
    void maintain(){
        s=ch[0]->s+ch[1]->s+1;
    }
    void pushdown(){
        if(flip){
            flip=0;
            swap(ch[0],ch[1]);
            ch[0]->flip^=1;
            ch[1]->flip^=1;
        }
    }
}pool[maxp];
Node *null=new Node();
int ph=0;
Node *newNode(){
    Node *n=&pool[ph++];
    n->flip=n->s=0;
    return n;
}
void rotate(Node *&o,int d){
    Node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
void splay(Node *&o,int k){
    o->pushdown();
    int d=o->cmp(k);
    if(d==1) k-=o->ch[0]->s+1;
    if(d!=-1){
        Node *p=o->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        int k2=(d2==0?k:k-p->ch[0]->s-1);
        if(d2!=-1){
            splay(p->ch[d2],k2);
            if(d==d2) rotate(o,d^1);else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}
Node* merge(Node *left,Node *right){
    splay(left,left->s);
    left->ch[1]=right;
    left->maintain();
    return left;
}
void split(Node *o,int k,Node *&left,Node *&right){
    splay(o,k);
    left=o;
    right=o->ch[1];
    o->ch[1]=null;
    left->maintain();
}
int num=0;
Node *build(int sz){
    if(sz==0) return null;
    Node *n=newNode();
    n->ch[0]=build(sz/2);
    n->val=num++;
    n->ch[1]=build(sz-sz/2-1);
    n->maintain();
    return n;
}
void print(Node *n){
    if(n==null) return;
    n->pushdown();
    print(n->ch[0]);
    if(n->val!=0)printf("%d\n",n->val);
    print(n->ch[1]);
}
int n,m;
int main(){
    freopen("/home/files/CppFiles/in","r",stdin);
    //freopen("defense.in","r",stdin);
    //freopen("defense.out","w",stdout);
    cin>>n>>m;
    Node *root=build(n+1);
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        Node *l,*r,*m,*o;
        split(root,a,l,o);
        split(o,b-a+1,m,r);
        m->flip^=1;
        root=merge(merge(l,r),m);
    }
    print(root);
    return 0;
}

时间: 2024-10-06 04:45:45

UVA 11922(Splay的相关文章

UVA 11922 Splay区间翻转+分裂+合并

- Permutation Transformer Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11922 Appoint description:  System Crawler  (2014-11-30) Description  Permutation Transformer  Write a program to transform th

uva 11922 - Permutation Transformer(伸展树)

题目链接:uva 11922 - Permutation Transformer 题目大意:给定一个序列,每次操作取出区间a~b,翻转后放到末尾,随后输出序列. 解题思路:就是伸展树,对于每个节点设一个flip,表示是否为翻转转态.每次将a旋转到根,然后分裂,再将b翻转到根,分裂,然后将mid翻转放到最后. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; str

【UOJ】【UR #2】猪猪侠再战括号序列(splay/贪心)

http://uoj.ac/problem/31 纪念伟大的没有调出来的splay... 竟然那个find那里写错了!!!!!!!!!!!!! 以后要记住:一定要好好想过! (正解的话我就不写了,太简单了.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #

uva 10065 (凸包+求面积)

链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=1006 Problem A Useless Tile Packers Input: standard input Output: standard output Yes, as you have apprehended the Useless Tile Pac

po3580SuperMemo(splay)

链接 操作不少,不过都是一些基本的操作,增删,旋转,逆转,询问最小. 注意一点:T<0时 让t=0: 旋转的时候,是顺时针旋转,数据范围在int内. 刚开始旋转转错方向了.. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #in

The Sultan&#39;s Successors UVA 167(八皇后问题)

说说: 其实这道题本质上就是一个八皇后问题.唯一的区别就是每个棋盘的格子都对应一个数字.最后要求输出,对应的解占据的格子的和的最大值.这只要在最后求出解的时候统计一下就可以了.下面就简单的说说八皇后问题,其实解法也不难.因为要求每行每列都要有棋子.因此只要确定每一行对应的棋子的列数就可以了.而对于每个棋子的所放的位置,同列上和对角线上不能有其他棋子,这个只要设一个访问数组保存一下就可以了.(注意要记得回溯).至于对角线的表示方法,例如所在位置为(x,y),那么一条对角线可以用x+y表示,另一条对

UVA 699(二叉树建树与遍历)

M - The Falling Leaves Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-02-08) Description  The Falling Leaves  Each year, fall in the North Central region is accompanied

UVA 548(二叉树重建与遍历)

J - Tree Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-05-16) Description  Tree  You are to determine the value of the leaf node in a given binary tree that is the ter

uva 11997 (基础数据结构)

题意: 有一个k*k 的方阵,让你从当中每一行挑选一个数字相加最后能得到K^K次方的和,输出其中最小的k个. 思路:先对每一行排序然后两两归并,每次取前k个再和下一行再进行归并.在归并的时候用一个优先队列维护最大的k个值每次先放k个进去然后一次每行和队顶比较,若是小则替换否则break最后输出即可. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <