splay

给定一个长度为 nn 的整数序列,初始时序列为 {1,2,,n1,n}{1,2,…,n−1,n}

序列中的位置从左到右依次标号为 1n1∼n

我们用 [l,r][l,r] 来表示从位置 ll 到位置 rr 之间(包括两端点)的所有数字构成的子序列。

现在要对该序列进行 mm 次操作,每次操作选定一个子序列 [l,r][l,r],并将该子序列中的所有数字进行翻转。

例如,对于现有序列 1 3 2 4 6 5 7,如果某次操作选定翻转子序列为 [3,6][3,6],那么经过这次操作后序列变为 1 3 5 6 4 2 7

请你求出经过 mm 次操作后的序列。

输入格式

第一行包含两个整数 n,mn,m

接下来 mm 行,每行包含两个整数 l,rl,r,用来描述一次操作。

输出格式

共一行,输出经过 mm 次操作后的序列。

数据范围

1n,m1051≤n,m≤105,
1lrn1≤l≤r≤n

输入样例:

6 3
2 4
1 5
3 5

输出样例:

5 2 1 4 3 6
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100010;
struct Node
{
    int s[2], p, v;
    int size,flag;

    void init(int _v, int _p)
    {
        v = _v, p = _p;
        size = 1;
    }
}tr[N];
int root, idx,m,n;

void pushup(int x) {
    tr[x].size = tr[tr[x].s[0]].size + tr[tr[x].s[1]].size + 1;
}

void pushdown(int x)
{
    if(tr[x].flag){
        swap(tr[x].s[0],tr[x].s[1]);
        tr[tr[x].s[0]].flag ^=1;
        tr[tr[x].s[1]].flag ^=1;
        tr[x].flag=0;
    }
}

void rotate(int x)  // 旋转
{
    int y = tr[x].p, z = tr[y].p;
    int k = tr[y].s[1] == x;
    tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;
    tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
    tr[x].s[k ^ 1] = y, tr[y].p = x;
    pushup(y), pushup(x);
}

void splay(int x, int k)  // splay操作
{
    while (tr[x].p != k)
    {
        int y = tr[x].p, z = tr[y].p;
        if (z != k)
            if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y)) rotate(x);
            else rotate(y);
        rotate(x);
    }
    if (!k) root = x;
}

void insert(int v){
    int u=root,p=0;
    while(u)p=u,u=tr[u].s[v>tr[u].v];
    u=++idx;
    if (p) tr[p].s[v>tr[p].v]=u;
    tr[u].init(v,p);
    splay(u,0);
}

int get_k(int k) {
    int u = root;
    while (true) {
        pushdown(u);
        if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0];
        else if (tr[tr[u].s[0]].size + 1 == k) return u;
        else k -= tr[tr[u].s[0]].size + 1, u = tr[u].s[1];
    }
    return -1;
}

void output(int u){
    pushdown(u);
    if (tr[u].s[0]) output(tr[u].s[0]);
    if (tr[u].v>=1&&tr[u].v<=n) cout<<tr[u].v<<" ";
    if (tr[u].s[1]) output(tr[u].s[1]);
}

int main(){
    scanf("%d%d", &n, &m);;
    for(int i=0;i<=n+1;i++) insert(i);
    while (m -- ){
        int l,r;
        scanf("%d%d", &l, &r);
        l= get_k(l),r= get_k(r+2);
        splay(l,0), splay(r,l);
        tr[tr[r].s[0]].flag^=1;
    }
    output(root);
    return 0;
}

 

给定一个长度为 nn 的整数序列,初始时序列为 {1,2,,n1,n}{1,2,…,n−1,n}

序列中的位置从左到右依次标号为 1n1∼n

我们用 [l,r][l,r] 来表示从位置 ll 到位置 rr 之间(包括两端点)的所有数字构成的子序列。

现在要对该序列进行 mm 次操作,每次操作选定一个子序列 [l,r][l,r],并将该子序列中的所有数字进行翻转。

例如,对于现有序列 1 3 2 4 6 5 7,如果某次操作选定翻转子序列为 [3,6][3,6],那么经过这次操作后序列变为 1 3 5 6 4 2 7

请你求出经过 mm 次操作后的序列。

输入格式

第一行包含两个整数 n,mn,m

接下来 mm 行,每行包含两个整数 l,rl,r,用来描述一次操作。

输出格式

共一行,输出经过 mm 次操作后的序列。

数据范围

1n,m1051≤n,m≤105,
1lrn1≤l≤r≤n

输入样例:

6 3
2 4
1 5
3 5

输出样例:

5 2 1 4 3 6
posted @ 2021-05-16 13:23  limited_Infinite  阅读(32)  评论(0编辑  收藏  举报
// //返回顶部 //返回顶部按钮