ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

文艺平衡树

2022-08-25 01:30:23  阅读:169  来源: 互联网

标签:sz lazy include int tr 文艺 平衡 now


# 【模板】文艺平衡树

## 题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列。

其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [2,4] 的话,结果是 5 2 3 4 1。

## 输入格式

第一行两个正整数 n,m,表示序列长度与操作个数。序列中第 i 项初始为 i。
接下来 m 行,每行两个正整数 l,r,表示翻转的区间。

## 输出格式

输出一行 n个正整数,表示原始序列经过 m 次变换后的结果。

 

题意:维护区间信息,每次会选择一个区间,翻转这个区间,最后输出区间的信息

做法:splay,FHGtreap

 

FHGtreap做法

要翻转l~r区间,就是先打上标记,然后再下传懒标记,首先把整棵树按树的大小分裂成x(1~l - 1), z(l~n), 再将z树分裂成y(l~r), z(r + 1, n),这个时候得到的y树就是整个要操作的区间,最后别忘了把x, y, z树合并返回根节点

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <set>
#include <map>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;

#define x first
#define y second

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
typedef pair<LL, LL> PLL;
const int N = 100010, M = 50000, mod = 998244353, INF = 0x3f3f3f3f, P = 1e8 - 3;

struct tree{
    int l, r;
    int val, key;
    int lazy, sz;
}tr[N];
int root, cnt;
int l, r;

int newNode(int val)
{
    tr[++ cnt].val = val;
    tr[cnt].key = rand();
    tr[cnt].sz = 1;
    return cnt;
}

void update(int now)
{
    tr[now].sz = tr[tr[now].l].sz + tr[tr[now].r].sz + 1;
}

void pushdown(int now)
{
    swap(tr[now].l, tr[now].r);
    tr[tr[now].l].lazy ^= 1;
    tr[tr[now].r].lazy ^= 1;
    tr[now].lazy = 0;
}

int x, y, z;

//按树的大小分裂 void spilt(int now, int sz, int &x, int &y) { if(!now) x = y = 0; else { if(tr[now].lazy) pushdown(now);//每次可能改变树的结构的操作前都要将懒标记下传 if(tr[tr[now].l].sz < sz) { x = now; spilt(tr[x].r, sz - tr[tr[now].l].sz - 1, tr[x].r, y); } else { y = now; spilt(tr[y].l, sz, x, tr[y].l); } update(now); } } int merge(int x, int y) { if(!x || !y) return x + y; else { if(tr[x].key > tr[y].key) { if(tr[x].lazy) pushdown(x); tr[x].r = merge(tr[x].r, y); update(x); return x; } else { if(tr[y].lazy) pushdown(y); tr[y].l = merge(x, tr[y].l); update(y); return y; } } } void ldr(int now) //输出中序遍历 { if(!now) return; if(tr[now].lazy) pushdown(now);//别忘了将剩下的懒标记下传 ldr(tr[now].l); printf("%d ", tr[now].val); ldr(tr[now].r); } void reverse(int l, int r) { spilt(root, l - 1, x, z); spilt(z, r - l + 1, y, z); tr[y].lazy ^= 1; merge(merge(x, y), z); } int main() { int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= n; i ++ ) root = merge(root, newNode(i)); while(m -- ) { scanf("%d %d", &l, &r); reverse(l, r); } ldr(root); return 0; }

 

splay:

把节点l转到根节点,再把r转到l的下面,这个时候节点r的左子树就是要操作的区间的子树,打上懒标记即可

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100010;

struct Node{
    int s[2], p, v;
    int sz, lazy;
    
    void init(int _v, int _p){
        v = _v, p = _p;
        sz = 1;
    }
}tr[N];
int root, idx;
int n, m;

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

void pushdown(int u)
{
    if(tr[u].lazy)
    {
        swap(tr[u].s[0], tr[u].s[1]);
        tr[tr[u].s[0]].lazy ^= 1;
        tr[tr[u].s[1]].lazy ^= 1;
        tr[u].lazy = 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) { while(tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if(z != k) if((tr[z].s[1] == y) ^ (tr[y].s[1] == x)) 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[p].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(u) { pushdown(u); if(tr[tr[u].s[0]].sz >= k) u = tr[u].s[0]; else if(tr[tr[u].s[0]].sz + 1 == k) return u; else k -= tr[tr[u].s[0]].sz + 1, u = tr[u].s[1]; } return -1; } void ldr(int u) { if(!u) return; pushdown(u); ldr(tr[u].s[0]); if(tr[u].v >= 1 && tr[u].v <= n) printf("%d ", tr[u].v); ldr(tr[u].s[1]); } int main() { cin >> n >> m; for(int i = 0; i <= n + 1; i ++ ) insert(i); while(m -- ) { int l, r; cin >> l >> r; l = get_k(l), r = get_k(r + 2); splay(l, 0), splay(r, l); tr[tr[r].s[0]].lazy ^= 1; } ldr(root); return 0; }

 

标签:sz,lazy,include,int,tr,文艺,平衡,now
来源: https://www.cnblogs.com/jay1573/p/16622916.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有