[bzoj1895][Pku3580]supermemo_非旋轉Treap
阿新 • • 發佈:2018-09-28
小結 fin 一個點 output 翻轉 旋轉 pac ron 平移
supermemo bzoj-1895 Pku-3580
題目大意:給定一個n個數的序列,需支持:區間加,區間翻轉,區間平移,單點插入,單點刪除,查詢區間最小值。
註釋:$1\le n\le 6.1\cdot 10^6$。
想法:
這數據範圍給的我真是醉了。
顯然用平衡樹,這裏用非旋轉Treap,題目讓你幹什麽你就幹什麽。
區間加:撕出子樹區間後打標記維護區間加。
區間翻轉:撕出子樹區間後打標記維護區間翻轉。
區間平移:相當於兩段相鄰區間交換,所以撕成四部分:左邊,第一個區間,第二個區間,右邊。然後按照左邊,第二個區間,第一個區間,右邊合並即可。
單點插入:將一個點當成一個非旋轉Treap,在插入位置左右撕開後將這個點放進去然後合上。
單點刪除:同理,刪除位置左,刪除節點,右撕開後,不管這個點,直接把左邊右邊合上。
最後,附上醜陋的代碼... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 1210010 using namespace std; struct Node { int ls,rs; int val,key; int size; int add,rev; int minn; }a[N]; int tot; struct par{int x,y;}; inline void pushup(int x) { int ls=a[x].ls,rs=a[x].rs; a[x].size=1; a[x].minn=a[x].val; if(ls) a[x].size+=a[ls].size,a[x].minn=min(a[x].minn,a[ls].minn); if(rs) a[x].size+=a[rs].size,a[x].minn=min(a[x].minn,a[rs].minn); } inline void pushdown(int x) { int ls=a[x].ls,rs=a[x].rs; if(a[x].rev) { if(ls) a[ls].rev^=1,swap(a[ls].ls,a[ls].rs); if(rs) a[rs].rev^=1,swap(a[rs].ls,a[rs].rs); a[x].rev=0; } if(a[x].add) { if(ls) a[ls].add+=a[x].add,a[ls].minn+=a[x].add,a[ls].val+=a[x].add; if(rs) a[rs].add+=a[x].add,a[rs].minn+=a[x].add,a[rs].val+=a[x].add; a[x].add=0; } } int merge(int x,int y) { if(!x||!y) return x|y; pushdown(x); pushdown(y); if(a[x].key>a[y].key) { a[x].rs=merge(a[x].rs,y); pushup(x); return x; } else { a[y].ls=merge(x,a[y].ls); pushup(y); return y; } } par split(int x,int k) { if(!k) return (par){0,x}; pushdown(x); int ls=a[x].ls,rs=a[x].rs; if(k==a[ls].size) { a[x].ls=0; pushup(x); return (par){ls,x}; } else if(k==a[ls].size+1) { a[x].rs=0; pushup(x); return (par){x,rs}; } else if(k<a[ls].size) { par t=split(ls,k); a[x].ls=t.y; pushup(x); return (par){t.x,x}; } else { par t=split(rs,k-a[ls].size-1); a[x].rs=t.x; pushup(x); return (par){x,t.y}; } } inline int newnode(int val) { tot++; a[tot].val=a[tot].minn=val; a[tot].ls=a[tot].rs=0; a[tot].size=1; a[tot].key=rand()*rand(); a[tot].rev=a[tot].add=0; return tot; } inline void update(int x,int val) { a[x].add+=val; a[x].minn+=val; a[x].val+=val; } inline void rev(int x) { a[x].rev^=1; swap(a[x].ls,a[x].rs); } int insert(int x,int k,int val) { par t=split(x,k); return merge(t.x,merge(newnode(val),t.y)); } void output(int x) { int ls=a[x].ls,rs=a[x].rs; if(ls) output(ls); printf("%d ",a[x].val); if(rs) output(rs); } int main() { // freopen("1895.in","r",stdin); // freopen("1895.out","w",stdout); srand(19260817); int n; cin >> n ; int root=1; int x; scanf("%d",&x); root=newnode(x); for(int i=2;i<=n;i++) { scanf("%d",&x); root=merge(root,newnode(x)); } int y,z; char opt[100]; int m; cin >> m ; for(int i=1;i<=m;i++) { scanf("%s",opt+1); if(opt[1]==‘A‘) { scanf("%d%d",&x,&y); par t1=split(root,x-1); par t2=split(t1.y,y-x+1); scanf("%d",&z); update(t2.x,z); root=merge(t1.x,merge(t2.x,t2.y)); } else if(opt[1]==‘R‘&&opt[4]==‘E‘) { scanf("%d%d",&x,&y); par t1=split(root,x-1); par t2=split(t1.y,y-x+1); rev(t2.x); root=merge(t1.x,merge(t2.x,t2.y)); } else if(opt[1]==‘R‘&&opt[4]==‘O‘) { scanf("%d%d%d",&x,&y,&z); par t1=split(root,x-1); par t2=split(t1.y,y-x+1); par t3=split(t2.x,a[t2.x].size-(z%a[t2.x].size)); root=merge(t1.x,merge(merge(t3.y,t3.x),t2.y)); } else if(opt[1]==‘I‘) { scanf("%d%d",&x,&y); y=newnode(y); par t=split(root,x); root=merge(t.x,merge(y,t.y)); } else if(opt[1]==‘D‘) { scanf("%d",&x); par t1=split(root,x-1); par t2=split(t1.y,1); root=merge(t1.x,t2.y); } else if(opt[1]==‘M‘) { scanf("%d%d",&x,&y); par t1=split(root,x-1); par t2=split(t1.y,y-x+1); printf("%d\n",a[t2.x].minn); root=merge(t1.x,merge(t2.x,t2.y)); } } return 0; }
小結:非旋轉Treap就是比splay優越!
[bzoj1895][Pku3580]supermemo_非旋轉Treap