博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ3580 SuperMemo(Splay的区间操作)
阅读量:7078 次
发布时间:2019-06-28

本文共 4366 字,大约阅读时间需要 14 分钟。

第一次写Splay的区间操作,调了5+小时……
Splay区间操作的核心就是区间的提取
例如:要提取[5, 12] 就要把4 Splay到根,把13 Splay到4的右儿子,那么13的左儿子就是[5, 12]的所有信息。

代码:

#include
#define MAXN 200005int tmp;inline void Swap(int &a, int &b) { tmp = a; a = b; b = tmp; }struct node { int sz, ch[2], f, v, mn, dv; bool rev; //mn:子树中的最小值,rev:是否经过翻转, dv:delta v,区间增减值的懒标记 inline void mt() {Swap(ch[0], ch[1]);}}t[MAXN];int rt, sz, n, m;inline void pushdown(int y) { if(t[y].rev) {t[y].mt(); if(t[y].ch[0]) t[t[y].ch[0]].rev ^= 1; if(t[y].ch[1]) t[t[y].ch[1]].rev ^= 1; t[y].rev = 0;} if(t[y].dv != 0) {t[y].v += t[y].dv; if(t[y].ch[0]) t[t[y].ch[0]].dv += t[y].dv; if(t[y].ch[1]) t[t[y].ch[1]].dv += t[y].dv; t[y].dv = 0;}}inline int Min(int a, int b) {
return a < b ? a : b;}inline void Upd(int r) { t[r].sz = t[t[r].ch[0]].sz + t[t[r].ch[1]].sz + 1; t[r].mn = Min(t[t[r].ch[0]].mn + t[t[r].ch[0]].dv, Min(t[t[r].ch[1]].mn + t[t[r].ch[1]].dv, t[r].v + t[r].dv));}inline void rot(int x){ int y = t[x].f, z = t[y].f; bool f = (t[y].ch[1] == x); pushdown(y);pushdown(x); t[y].ch[f] = t[x].ch[f^1]; if(t[y].ch[f]) t[t[y].ch[f]].f = y; t[x].ch[f^1] = y; t[y].f = x; t[x].f = z; if(z) t[z].ch[t[z].ch[1]==y] = x; Upd(y);}void Splay(int r, int tp, int &Root = rt) { for(int y, z; (y = t[r].f) != tp; rot(r)) { pushdown(r); z = t[y].f; if(z == tp) continue; if( (t[z].ch[0] == y) == (t[y].ch[0] == r) ) rot(y); else rot(r); } if(!tp) Root = r; Upd(r);}int Kth(int x, int &Root = rt){ int y = Root, p; if(x>t[Root].sz)return 0; while(1) { pushdown(y); Upd(y); p=t[y].ch[0]; if(t[p].sz+1
=x) y=p; else break; } Splay(y, 0, Root); return y;}int a[MAXN];int Build(int l, int r) { //把初始区间建成二叉树 if(l > r) return 0; int mid = (l + r) >> 1; t[mid].ch[0] = Build(l, mid-1); t[mid].ch[1] = Build(mid+1, r); t[mid].v = t[mid].mn = a[mid]; Upd(mid); if(t[mid].ch[0]) t[t[mid].ch[0]].f = mid; if(t[mid].ch[1]) t[t[mid].ch[1]].f = mid; return mid;}inline void Rev(int l, int r) { //区间翻转 int b = Kth(r+2), a = Kth(l); Splay(b, a); int p = t[b].ch[0]; t[p].rev ^= 1;}inline void Add(int l, int r, int w) {
//区间增加 int b = Kth(r+2), a = Kth(l); Splay(b, a); int p = t[b].ch[0]; t[p].dv += w; Upd(b); Upd(a);}inline int QMIN(int l, int r) {
//区间最小值 int b = Kth(r+2), a = Kth(l); Splay(b, a); int p = t[b].ch[0]; Upd(b); Upd(a); return t[p].mn + t[p].dv; //一定要加t[p].dv!!!}inline void Merge(int &left, int right) {
//区间合并 int p = rt; while(t[p].ch[1]) p = t[p].ch[1]; Splay(p, 0, left); t[left].ch[1] = right; t[right].f = left; Upd(left);}inline void split(int &x, int k, int &left, int &right) {
//区间分离 Kth(k, x); left = x; right = t[x].ch[1]; t[right].f = 0; t[x].ch[1] = 0; Upd(left);}void Revolve(int l, int r, int T) //题目中定义的Revolve操作{ T = T%(r-l+1)+(r-l+1); //discuss里面说T可能为负数…… T %= (r-l+1); if (!T) return; Rev(l, r); Rev(l, l+T-1); Rev(l+T, r);}void Del(int k){ int t1, t2, t3; split(rt, k, t1, t2); split(t2, 1, t2, t3); Merge(t1, t3); rt = t1;}char c, f;inline void GET(int &n) { n = 0; f = 1; do {c = getchar(); if(c == '-') f = -1;} while(c > '9' || c < '0'); while(c >= '0' && c <= '9') {n=n*10+c-'0';c=getchar();} n *= f;}void Ins(int k, int x){ ++ sz; t[sz].v = t[sz].mn = x; t[sz].sz = 1; int t1, t2; split(rt, k+1, t1, t2); Merge(t1, sz); Merge(t1, t2); rt = t1;}int main() { int t1, t2, t3; GET(n); a[1] = a[n+2] = ~0U>>2; t[0].mn = ~0U>>2; for(int i = 1; i <= n; i ++) GET(a[i+1]); rt = Build(1, n+2); sz = n+4; GET(m); char s[10]; while(m --) { scanf("%s", s); if(s[0] == 'A') { GET(t1); GET(t2); GET(t3); Add(t1, t2, t3); } else if(s[0] == 'M') { GET(t1); GET(t2); printf("%d\n", QMIN(t1, t2)); } else if(s[0] == 'I') { GET(t1); GET(t2); Ins(t1, t2); } else if(s[0] == 'D') { GET(t1); Del(t1); } else if(s[3] == 'E') { GET(t1); GET(t2); Rev(t1, t2); } else { GET(t1); GET(t2); GET(t3); Revolve(t1, t2, t3); } }}

转载于:https://www.cnblogs.com/geng4512/p/5296887.html

你可能感兴趣的文章
【C#】LINK LABEL的使用技巧
查看>>
java 回调函数
查看>>
高清壁纸:非常漂亮的2013年5月日历桌面壁纸下载
查看>>
vwallpaper2支持来电视频了!附简单教程
查看>>
pku 1691 Painting A Board DFS 抽象建图 + 拓扑排序
查看>>
OpenCV图像转换
查看>>
文件的属性(转)
查看>>
linux邮件系统(报警) POSTFIX AND DOVECOT
查看>>
(DevExpress2011控件教程)ASPxGridView 范例3 :ASPxGridView 排序和分组、过滤行、统计功能等功能实现...
查看>>
基本排序排序算法
查看>>
第十八章 29创建可自动调节大小的string类字符串对象
查看>>
Latex多行公式的处理[转]
查看>>
操作符重载
查看>>
SQLPLUS工具简介
查看>>
AnDroidDraw+DroidDraw实现Android程序UI设计
查看>>
Multipatch 从点文件生成multipatch
查看>>
iOS模拟器,点击textfield为什么不弹出软键盘
查看>>
Jetty 7.6.8 和 8.1.8 发布
查看>>
程序员如何做出“不难看”的设计
查看>>
类苹果启动器 Cairo Dock 3.1.2 稳定版发布
查看>>