POJ3580 SuperMemo(Splay的区间操作)

来源:互联网 发布:残疾人产品设计 知乎 编辑:程序博客网 时间:2024/05/02 00:16

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

代码:

#include<cstdio>#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) {            x-=t[p].sz+1;            y=t[y].ch[1];        }        else if(t[p].sz>=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);        }    }}
0 0
原创粉丝点击