uva 11922 - Permutation Transformer(伸展树)

题目链接:uva 11922 - Permutation Transformer

题目大意:给定一个序列,每次操作取出区间a~b,翻转后放到末尾,随后输出序列。

解题思路:就是伸展树,对于每个节点设一个flip,表示是否为翻转转态。每次将a旋转到根,然后分裂,再将b翻转到根,分裂,然后将mid翻转放到最后。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct Node {
    int val, sum, flip;
    Node* cid[2];

    Node(int val = 0);
    int cmp (int v);
    void maintain();
    void pushdown();
};

void rotate (Node* &o, int d);

void build(Node* &o, int l, int r);
void put(Node* &o);
void split (Node* o, int k, Node* &l, Node* & r);
Node* merge (Node* l, Node* r);
void splay(Node* &o, int k);

int main () {
    int n, m, x, y;
    while (scanf("%d%d", &n, &m) == 2) {
        Node* root = NULL;
        Node *l, *mid, *r, *o;

        build(root, 0, n);

        for (int i = 0; i < m; i++) {
            scanf("%d%d", &x, &y);

            split(root, x, l, o);
            split(o, y - x + 1, mid, r);

            mid->flip ^= 1;
            root = merge(merge(l, r), mid);
        }
        put(root);
    }
    return 0;
}

void splay(Node* &o, int k) {

    o->pushdown();
    int d = o->cmp(k);

    if (d == 1) k -= (o->cid[0] == NULL ? 0 : o->cid[0]->sum) + 1;

    if (d != -1) {
        Node* p = o->cid[d];
        p->pushdown();

        int d2 = p->cmp(k);
        int k2 = (d2 == 0 ? k : k - (p->cid[0] == NULL ? 0 : p->cid[0]->sum) - 1);
        if (d2 != -1) {
            splay(p->cid[d2], k2);
            if (d == d2)
                rotate(o, d^1);
            else
                rotate(o->cid[d], d);
        }
        rotate(o, d^1);
    }
}

Node* merge (Node* l, Node* r) {
    splay(l, l->sum);
    l->cid[1] = r;
    l->maintain();
    return l;
}

void split (Node* o, int k, Node* &l, Node* & r) {
    splay(o, k);
    l = o;
    r = o->cid[1];
    o->cid[1] = NULL;
    l->maintain();
}

void build(Node* &o, int l, int r) {
    if (l > r)
        return;

    int mid = (l + r) / 2;
    o = new Node(mid);
    build(o->cid[0], l, mid - 1);
    build(o->cid[1], mid + 1, r);
    o->maintain();
}

void rotate (Node* &o, int d) {
    Node* k = o->cid[d^1];
    o->cid[d^1] = k->cid[d];
    k->cid[d] = o;
    o->maintain();
    k->maintain();
    o = k;
}

void put(Node* &o) {
    o->pushdown();
    if (o->cid[0] != NULL) put(o->cid[0]);
    if (o->val)
        printf("%d\n", o->val);
    if (o->cid[1] != NULL) put(o->cid[1]);

    delete o;
    o = NULL;
}

Node::Node (int val) {
    sum = 1;
    flip = 0;
    this->val = val;
    cid[0] = cid[1] = NULL;
}

int Node::cmp (int v) {
    int d = v - (cid[0] == NULL ? 0 : cid[0]->sum);
    if (d == 1) return -1;
    return d <= 0 ? 0 : 1;
}

void Node::pushdown() {
    if (flip) {
        flip = 0;
        swap(cid[0], cid[1]);
        if (cid[0] != NULL)
            cid[0]->flip = !cid[0]->flip;
        if (cid[1] != NULL)
            cid[1]->flip = !cid[1]->flip;
    }
}

void Node::maintain () {
    sum = 1;
    if (cid[0] != NULL) sum += cid[0]->sum;
    if (cid[1] != NULL) sum += cid[1]->sum;
}

void remove (Node* &o) {
    if (o->cid[0] != NULL) remove(o->cid[0]);
    if (o->cid[1] != NULL) remove(o->cid[1]);
    delete o;
    o = NULL;
}
时间: 2024-10-03 00:50:46

uva 11922 - Permutation Transformer(伸展树)的相关文章

UVA 11922 Permutation Transformer —— splay伸展树

题意:根据m条指令改变排列1 2 3 4 - n ,每条指令(a, b)表示取出第a~b个元素,反转后添加到排列尾部 分析:用一个可分裂合并的序列来表示整个序列,截取一段可以用两次分裂一次合并实现,粘贴到末尾可以用一次合并实现. 翻转可以采用在每个结点上做标记的方法,flip = 1意味着将这棵子树翻转,可以类似线段树用一个pushdown()实现标记向下传递. 可以发现当前排列就是伸展树的中序遍历序列.中序遍历打印结果即可. 注意代码中设置了虚拟首结点0的技巧. 代码如下: 1 #includ

Uva 11922 Permutation Transformer

闲的没事打了打一个splay,,,,, 注意只要是遍历数据结构就要下传标记!!!! 只要是修改就要维护所有受到影响的!!! 希望以后不要再犯这种zz错误了hhh #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> #define ll long long #define m

11922 - Permutation Transformer (Splay区间翻转)

UVA 11922 - Permutation Transformer 题目链接 题意:给一个序列,每次操作选择(a,b),把(a,b)序列翻转之后加到末尾,求最终序列 思路:Splay的应用,多一个flip标记,在开头多一个虚拟的0结点,这样每次就利用Splay进行分裂合并即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include

uva 11922 Permutation Transforme/splay tree

原题链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18902 伸展树的区间翻转剪切... 如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<algorithm> 5 const int Max_N = 100010; 6 struct Node{ 7 int v, s, rev;

UVA 11525 Permutation ——(线段树,脑筋急转弯)

只要注意到对于譬如:S1*(k-1)! 因为后面k-1个数字的全排列个数刚好是(k-1)!,那么第一个数字就是没有取过的数字的第(S1+1)个即可.取走这个数字以后这个数字就不能再用了,依次类推即可得到整个排列了. 那么随便用线段树维护一下即可. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define t_mid (l+r>>1) 5 #define

UVA11922--Permutation Transformer (伸展树Splay)

题意:m条操作指令,对于指令 a  b 表示取出第a~b个元素,翻转后添加到排列的尾部. 水题卡了一个小时,一直过不了样例.  原来是 dfs输出的时候 忘记向下传递标记了. 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const double eps = 1e-8; 7 const

UVA 11525 Permutation(树状数组)

题目意思是说  给你一个数k  然后有k个si   问你1--k 的第n个全排列是多少   注意是 1 2 3...k的全排列 不是si的 N=   由观察得知(k-i)!就是k-i个数字的全排列种数, 0=<Si<=k-i,所以显然可知假设当i==1时从第(k-1)!*s1到第n个全排列都是由第S1+1个数字开始的数列,因为每(k-1)!次排列过后,下一个排列的第1个数字都要增大1(每隔(k-1)!次,这k-1个数字都排列过一遍了,下一次只能增大更前面一个,也就是第1个了) 比如对于数列{1

uva 11525 - Permutation(线段树)

题目链接:uva 11525 - Permutation 题目大意:给定n和k,n给定的方式为k个si,根据公式计算出n,求一个由1~k组成的长度为k的序列的第n个排序 解题思路:根据公式的性质,等于对于每个位置找当前状态下第si小的数.线段树子节点均为1,维护和,查询时传入参数查找即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int ma

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