洛谷 P3391 【模板】文艺平衡树(Splay)

先记一发非旋treap,splay什么的以后再说

基本就是正常的非旋treap维护序列加上一个flip标记,如果某个节点flip为true表示以它为根的子树需要一次翻转。类似线段树lazytag

每次可能要修改某个节点o的任意ch之前,都对o进行一次pushdown。(就是split和merge中)

pushdown的操作是交换o的两个子节点,再将两个子节点的flip标记异或1。

每次进行翻转操作(翻转[l,r]),就把整个序列split成三段[1,l-1],[l,r],[r+1,size]。然后直接将中间一段的根节点的flip标记异或1,再merge回去就行了。

曾经错误:72行两个语句反了;实际上flip不需要修改split和merge,不要多此一举

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<ctime>
  4 using namespace std;
  5 template<typename T>
  6 class MyVec
  7 {
  8 private:
  9     static const int M_SIZE=200001;
 10     int rand1()
 11     {
 12         static int x=471;
 13         return x=(48271LL*x+1)%2147483647;
 14     }
 15 public:
 16     struct Node
 17     {
 18         Node(){}
 19         Node* ch[2];
 20         int r;
 21         bool flip;
 22         //表示该节点的所有子节点需要flip
 23         T v;
 24         int size;
 25         void upd()
 26         {
 27             size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0);
 28         }
 29         void pushdown()
 30         {
 31             if(flip)
 32             {
 33                 Node* t=ch[0];ch[0]=ch[1];ch[1]=t;
 34                 if(ch[0])    (ch[0]->flip)^=1;
 35                 if(ch[1])    (ch[1]->flip)^=1;
 36                 flip=0;
 37             }
 38         }
 39     }nodes[M_SIZE];
 40 private:
 41     Node* root;
 42     Node* que[M_SIZE];
 43     int que_top;
 44     Node* getnode()
 45     {
 46         return que[que_top--];
 47     }
 48     void delnode(Node* x)
 49     {
 50         que[++que_top]=x;
 51     }
 52     Node* merge(Node* a,Node* b)
 53     {
 54         if(a==NULL)    return b;
 55         if(b==NULL)    return a;
 56         if(a->r < b->r)
 57         {
 58             a->pushdown();a->ch[1]=merge(a->ch[1],b);a->upd();
 59             return a;
 60         }
 61         else
 62         {
 63             b->pushdown();b->ch[0]=merge(a,b->ch[0]);b->upd();
 64             return b;
 65         }
 66     }
 67     typedef pair<Node*,Node*> P;
 68     P split(Node* a,int n)
 69     {
 70         if(a==NULL)    return P(NULL,NULL);
 71         P y;
 72         a->pushdown();int s=a->ch[0] ? a->ch[0]->size : 0;
 73         if(s>=n)
 74         {
 75             y=split(a->ch[0],n);
 76             a->ch[0]=y.second;a->upd();
 77             y.second=a;
 78         }
 79         else
 80         {
 81             y=split(a->ch[1],n-s-1);
 82             a->ch[1]=y.first;a->upd();
 83             y.first=a;
 84         }
 85         return y;
 86     }
 87     Node* kth(Node* o,int k)
 88     {
 89         if(o==NULL||k<=0||k > o->size)    return NULL;
 90         P y=split(root,k-1);
 91         P y2=split(y.second,1);
 92         root=merge(merge(y.first,y2.first),y2.second);
 93         return y2.first;
 94     }
 95     void erase(Node* &o,int k)
 96     {
 97         if(o==NULL||k<=0||k > o->size)    return;
 98         P y=split(root,k-1);
 99         P y2=split(y.second,1);
100         delnode(y2.first);
101         root=merge(y.first,y2.second);
102     }
103 public:
104     //在第k个之前插入
105     void insert(int k,const T& x)
106     {
107         Node* t=getnode();
108         t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=x;t->flip=0;t->upd();
109         P y=split(root,k-1);
110         root=merge(merge(y.first,t),y.second);
111     }
112     MyVec()
113     {
114         que_top=M_SIZE-1;
115         for(int i=0;i<M_SIZE;i++)    que[i]=nodes+i;
116         root=NULL;
117     }
118     void push_back(const T& x)
119     {
120         insert(size()+1,x);
121     }
122     void pop_back()
123     {
124         erase(root,root->size);
125     }
126     void push_front(const T& x)
127     {
128         insert(1,x);
129     }
130     void pop_front()
131     {
132         erase(root,1);
133     }
134     Node* find_by_order(int k)
135     {
136         return kth(root,k);
137     }
138     T& operator[](int k)
139     {
140         return kth(root,k)->v;
141     }
142     void erase(int k)
143     {
144         erase(root,k);
145     }
146     int size()
147     {
148         return root ? root->size : 0;
149     }
150     //翻转[l,r]
151     void flip(int l,int r)
152     {
153         P y=split(root,l-1);
154         P y2=split(y.second,r-l+1);
155         y2.first->flip^=1;
156         root=merge(merge(y.first,y2.first),y2.second);
157     }
158 };
159 MyVec<int> x;
160 int n,m,l,r;
161 int main()
162 {
163     int i;
164     scanf("%d%d",&n,&m);
165     for(i=1;i<=n;i++)
166         x.push_back(i);
167     while(m--)
168     {
169         scanf("%d%d",&l,&r);
170         x.flip(l,r);
171     }
172     for(i=1;i<=n;i++)
173         printf("%d ",x[i]);
174     return 0;
175 }
时间: 2024-10-16 13:43:20

洛谷 P3391 【模板】文艺平衡树(Splay)的相关文章

洛谷P3391 【模板】文艺平衡树(Splay)

题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入输出格式 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r

洛谷P3391 【模板】文艺平衡树(Splay)(FHQ Treap)

题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入输出格式 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r

洛谷 P3391 【模板】文艺平衡树(Splay)

题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是 (1,2,?n?1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1≤l≤r≤n 输出格式: 输出一行n个数字,表示原始序列经过m次变换后的结果

AC日记——文艺平衡树 洛谷 P3391

文艺平衡树 思路: splay翻转操作模板: 虚拟最左最右端点,然后每次都把l翻转到root,r+2翻转到root的右节点: 然后在r+2的左节点上打标记: 标记需要在旋转,rank,print时下放: 建树需要用完全平衡二叉树: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define m

Tyvj P1729 文艺平衡树 Splay

题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数

BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3595  Solved: 2029[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

洛谷3380 二逼平衡树(树套树)

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647) 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647) 注意上面两条要求和tyvj或者bzoj不一样,请注意 输入输出格式 输入格式: 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例:

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整