• SPOJ GSS1 ~ 8解题报告 【完整版】


    若转载请注明出处!!!

    GSS1 —— GSS8 简述做法加代码。

    GSS1

    给出了序列(A[1])(A[2]),…,(A[N])((a[i]≤15007,1≤N≤50000))。查询定义如下: 查询((x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y})。 给定M个查询,程序必须输出这些查询的结果。

    思路:

    我们维护四个值:

    sum, lsum, rsum, msum
    

    然后进行更新,静态查询即可。

    具体讲解见 这里了啦

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 50010
    #define inf 1 << 30
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    struct tree{
        int lsum, rsum, sum, msum;
    } z[mn << 2];
    inline void update(int rt){
        z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
        z[rt].lsum = max(z[rt << 1].lsum, z[rt << 1].sum + z[rt << 1 | 1].lsum);
        z[rt].rsum = max(z[rt << 1 | 1].rsum, z[rt << 1 | 1].sum + z[rt << 1].rsum);
        z[rt].msum = max(max(z[rt << 1].msum, z[rt << 1 | 1].msum), z[rt << 1].rsum + z[rt << 1 | 1].lsum);
    }
    inline void build(int l,int r,int rt){
        if(l==r){
            z[rt].sum = z[rt].lsum = z[rt].rsum = z[rt].msum = read();
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        update(rt);
    }
    inline tree query(int l,int r,int rt,int nowl,int nowr){
        if(nowl<=l && r<=nowr){return z[rt];}
        int m = (l + r) >> 1;
        bool fl = false, fr = false;
        tree tl, tr, res;
        if (nowl <= m){
            if(m<nowr){
                tl = query(lson, nowl, nowr);
                tr = query(rson, nowl, nowr);
                res.sum = tl.sum + tr.sum;
                res.lsum = max(tl.lsum, tl.sum + tr.lsum);
                res.rsum = max(tr.rsum, tr.sum + tl.rsum);
                res.msum = max(max(tl.msum, tr.msum), tl.rsum + tr.lsum);
                return res;
            }else{
                return query(lson, nowl, nowr);
            }
        }else{
            return query(rson, nowl, nowr);
        }
    }
    int n, m;
    int main(){
        n = read();
        build(root);
        m = read();
        go(i, 1, m, 1) {
            int x = read(), y = read();
            cout << query(root, x, y).msum << "
    ";
        }
        return 0;
    }
    
    

    GSS2

    给出 (n) 个数,(q) 次询问,求最大子段和,相同的数只算一次。

    思路:

    因为没有修改,我们考虑离线做。

    我们把询问 ([l, r]) 按照 (r) 的升序排序,在线段树内维护 (sum) 和 它的历史最大值 (hmax),我们可以记 (pre[i]) 作为第 (i) 个元素的上一个元素的位置。

    我们把原数组按读入顺序加入,我们只需要把这个 (a[i]) 在区间 ([pre[i] + 1, i]) 上区间加即可,然后查询时直接查询 ([l, r]) 的历史最大值。

    记得加上维护左右儿子的 (sum) 最大值和左右儿子 (hmax) 的最大值,这样我们才能更新 本节点的 (hmax)

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 100010
    #define inf 1 << 30
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    struct Que{
        ll l, r, id;
    } q[mn];
    ll b[mn], ans[mn];
    ll pre[mn << 1], suf[mn << 1];
    inline bool cmp(Que a,Que b){
        return a.r < b.r;
    }
    struct tree{
        ll sum, hsum, cols, hcol;
    };
    struct SegmentTree{
        tree z[mn << 2];
        inline tree operation(tree a,tree b){
            return (tree){max(a.sum, b.sum), max(a.hsum, b.hsum)};
        }
        inline void update(int rt){
            z[rt].sum = max(z[rt << 1].sum, z[rt << 1 | 1].sum);
            z[rt].hsum = max(z[rt << 1].hsum, z[rt << 1 | 1].hsum);
        }
        inline void color(int l, int r, int rt){
            z[rt].hsum = max(z[rt].hsum, z[rt >> 1].hcol + z[rt].sum);
            z[rt].sum += z[rt >> 1].cols;
            z[rt].hcol = max(z[rt].hcol, z[rt >> 1].hcol + z[rt].cols);
            z[rt].cols += z[rt >> 1].cols;
        }
        inline void coloring(int l,int r,int rt,ll v){
            z[rt].sum += v;
            z[rt].hsum = max(z[rt].sum, z[rt].hsum);
            z[rt].cols += v;
            z[rt].hcol = max(z[rt].cols, z[rt].hcol);
        }
        inline void push_col(int l,int r,int rt){
            int m = (l + r) >> 1;
            color(lson);
            color(rson);
            z[rt].hcol = z[rt].cols = 0;
        }
        inline void modify(int l,int r,int rt,int nowl,int nowr,ll v){
            if(nowl<=l && r<=nowr){
                coloring(bson,v);
                return;
            }
            int m = (l + r) >> 1;
            push_col(bson);
            if (nowl <= m)
                modify(lson, nowl, nowr, v);
            if(m<nowr)
                modify(rson, nowl, nowr, v);
            update(rt);
        }
        inline tree query(int l,int r,int rt,int nowl,int nowr){
            if(nowl<=l && r<=nowr)
                return z[rt];
            int m = (l + r) >> 1;
            push_col(bson);
            if(nowl<=m){
                if(m<nowr)
                    return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
                else
                    return query(lson, nowl, nowr);
            }else{
                return query(rson, nowl, nowr);
            }
        }
    } tr;
    int n, m;
    int main(){
        n = read();
        go(i, 1, n, 1) b[i] = read(), pre[i] = suf[b[i] + 100000], suf[b[i] + 100000] = i;
        m = read();
        go(i, 1, m, 1) q[i].l = read(), q[i].r = read(), q[i].id = i;
        sort(q + 1, q + m + 1, cmp);
        int y = 1;
        go(i, 1, n, 1){
            tr.modify(root, pre[i] + 1, i, b[i]);
            while(y<=m&&q[y].r<=i){
                ans[q[y].id] = tr.query(root, q[y].l, q[y].r).hsum;
                y++;
            }
        }
        go(i, 1, m, 1)
            printf("%lld
    ", ans[i]);
        return 0;
    }
    
    

    GSS3

    (n) 个数,(q) 次操作

    • 0 (x) (y)(A_x) 修改为 (y)

    • 1 (l) (r) 询问区间 ([l, r]) 的最大子段和

    思路

    直接在GSS1代码里加上单点加就好,没什么其他注意的。

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 100010
    #define inf 1 << 30
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    struct tree{
        int sum, lsum, rsum, msum;
    } z[mn << 2];
    inline void update(int rt){
        z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
        z[rt].lsum = max(z[rt << 1].lsum, z[rt << 1 | 1].lsum + z[rt << 1].sum);
        z[rt].rsum = max(z[rt << 1 | 1].rsum, z[rt << 1].rsum + z[rt << 1 | 1].sum);
        z[rt].msum = max(max(z[rt << 1].msum, z[rt << 1 | 1].msum), z[rt << 1].rsum + z[rt << 1 | 1].lsum);
    }
    inline void build(int l,int r,int rt){
        if(l==r){
            z[rt].sum = z[rt].lsum = z[rt].rsum = z[rt].msum = read();
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        update(rt);
    }
    inline void modify(int l,int r,int rt,int now,int v){
        if(l==r && l==now){
            z[rt].sum = z[rt].rsum = z[rt].msum = z[rt].lsum = v;
            return;
        }
        int m = (l + r) >> 1;
        //push_col(bson);
        if(now<=m)
            modify(lson, now, v);
        else
            modify(rson, now, v);
        update(rt);
    }
    inline tree query(int l,int r,int rt,int nowl,int nowr){
        if(nowl<=l && r<=nowr){
            //cout << z[rt].msum << " ";
            return z[rt];
        }
        int m = (l + r) >> 1;
        //push_col(bson);
        tree tl, tr, res;
        if(nowl<=m){
            if(m<nowr){
                tl = query(lson, nowl, nowr);
                tr = query(rson, nowl, nowr);
                res.sum = tl.sum + tr.sum;
                res.lsum = max(tl.lsum, tl.sum + tr.lsum);
                res.rsum = max(tr.rsum, tr.sum + tl.rsum);
                res.msum = max(max(tl.msum, tr.msum), tl.rsum + tr.lsum);
                return res;
            }else
                return query(lson, nowl, nowr);
            
        }else{
            return query(rson, nowl, nowr);
        }
    }
    int n, m;
    int main(){
        n = read();
        build(root);
        m = read();
        go(i,1,m,1){
            int s = read();
            if(!s){
                int x = read(), y = read();
                modify(root, x, y);
            }else{
                int x = read(), y = read();
                cout << query(root, x, y).msum << "
    ";
            }
        }
        return 0;
    }
    
    

    GSS4

    「题意」: (n) 个数,和在 (10 ^ {18})

    现在有「两种」操作

    • 0 (x) (y) 把区间 ([x,y]) 内的每个数开方,下取整

    • 1 (x) (y) 询问区间 ([x,y]) 的每个数的和

    「格式」: 有多组数据,数据以EOF结束,对于每组数据,输出数据的序号,每组数据之后输出一个空行。

    「注意」: 不保证给出的区间 ([x, y])(x <= y) ,如果 (x > y) 请交换(x)(y)

    思路

    如果数据都在 10 ^ 18 那说明我们如果此次开方的话,肯定在很快的几次开方后变成了 1 ,所以,如果这个区间的数字开方开着开着都变成了 1, 那么就没必要在去开方了。经计算,每个数最多开 7 ~ 8 次(保守说的),所以我们直接暴力在线段树上修改最多会修改 8 * N * logN。

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 100010
    #define inf 1 << 30
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline ll read(){
        ll f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    ll z[mn << 2];
    inline void update(int rt){
        z[rt] = z[rt << 1] + z[rt << 1 | 1];
    }
    inline void build(int l,int r,int rt){
        if(l==r){
            z[rt] = read();
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        update(rt);
    }
    inline void modify(int l,int r,int rt,int nowl,int nowr){
        if(r-l+1 == z[rt])
            return;
        if(l==r){
            z[rt] = sqrt(z[rt]);
            return;
        }
        int m = (l + r) >> 1;
        if(nowl<=m)
            modify(lson, nowl, nowr);
        if(m<nowr)
            modify(rson, nowl, nowr);
        update(rt);
    }
    inline ll query(int l,int r,int rt,int nowl,int nowr){
        if(nowl<=l && r<=nowr){
            return z[rt];
        }
        int m = (l + r) >> 1;
        if(nowl<=m){
            if(m<nowr)
                return query(lson, nowl, nowr) + query(rson, nowl, nowr);
            else
                return query(lson, nowl, nowr);
        }else{
            return query(rson, nowl, nowr);
        }
    }
    int n, m, tot;
    int main(){
        while (scanf("%d", &n) != EOF){
            printf("Case #%d:
    ", ++tot);
            build(root);
            m = read();
            go(i, 1, m, 1){
                int s = read(), x = read(), y = read();
                if(x>y)
                    swap(x, y);
                if(!s){
                    modify(root, x, y);
                }else{
                    printf("%lld
    ", query(root, x, y));
                }
            }
            putchar('
    ');
        }
        return 0;
    }
    
    

    GSS5

    给定一个序列。查询左端点在([x_1, y_1])之间,且右端点在([x_2, y_2])之间的最大子段和,数据保证(x_1 <= x_2), (y_1 <= y_2),但是不保证端点所在的区间不重合

    思路

    我们考虑分类讨论。

    首先是(y_1 <= x_2)的情况,这种情况说明,([y_1, x_2])必定在答案的和之中,我们要求的就是([x_1, y_1])的最大后缀和,加上([x_2, y_2])的最大前缀和,加上([y_1, x_2])的区间和。

    然后就是一个比较麻烦的情况,(y_1 > x_2)

    这种情况可能有三种最佳答案。一种是以 (y_1) 为分界的最大后缀和(区间([x_1, y_1]))与最大前缀和(([y_1, y_2])),一种是以 (x_2) 为分界的最大后缀和(([x_1, x_2]))与最大前缀和(([x_2, y_2])),第三种就是所取答案都在 ([x_2, y_1]) 中。

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 50010
    #define inf 1 << 30
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    struct tree{
        int lsum, rsum, sum, msum;
    } z[mn << 2];
    int a[mn];
    inline void update(int rt){
        z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
        z[rt].lsum = max(z[rt << 1].lsum, z[rt << 1].sum + z[rt << 1 | 1].lsum);
        z[rt].rsum = max(z[rt << 1 | 1].rsum, z[rt << 1 | 1].sum + z[rt << 1].rsum);
        z[rt].msum = max(max(z[rt << 1].msum, z[rt << 1 | 1].msum), z[rt << 1].rsum + z[rt << 1 | 1].lsum);
    }
    inline void build(int l,int r,int rt){
        if(l==r){
            z[rt].sum = z[rt].lsum = z[rt].rsum = z[rt].msum = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        update(rt);
    }
    inline tree query(int l,int r,int rt,int nowl,int nowr){
        if(nowl<=l && r<=nowr){return z[rt];}
        int m = (l + r) >> 1;
        bool fl = false, fr = false;
        tree tl, tr, res;
        if (nowl <= m){
            if(m<nowr){
                tl = query(lson, nowl, nowr);
                tr = query(rson, nowl, nowr);
                res.sum = tl.sum + tr.sum;
                res.lsum = max(tl.lsum, tl.sum + tr.lsum);
                res.rsum = max(tr.rsum, tr.sum + tl.rsum);
                res.msum = max(max(tl.msum, tr.msum), tl.rsum + tr.lsum);
                return res;
            }else{
                return query(lson, nowl, nowr);
            }
        }else{
            return query(rson, nowl, nowr);
        }
    }
    int n, m;
    inline void solve() {
        n = read();
        go(i, 1, n, 1) a[i] = read();
        build(root);
        m = read();
        go(i, 1, m, 1) {
            int x = read(), y = read(), xx = read(), yy = read();
            if(y < xx) {
            	int ans = 0;
            	ans += query(root, x, y).rsum;
            	if(y + 1 <= xx - 1) 
                	ans += query(root, y + 1, xx - 1).sum;
            	ans += query(root, xx, yy).lsum;
            	printf("%d
    ", ans);
            } else {
                int ans = 0;
                ans = query(root, xx, y).msum;
                if(x < xx) ans = max(ans, query(root, x, xx).rsum + query(root, xx, yy).lsum - a[xx]);
                if(y < yy) ans = max(ans, query(root, x, y).rsum + query(root, y, yy).lsum - a[y]);
                printf("%d
    ", ans);
            }
        }
    }
    inline void init() {
        memset(z, 0, sizeof z);
    }
    int main(){
        int T = read();
        while(T--) {
        	init();
        	solve();
        }
        return 0;
    }
    
    

    GSS6

    给出一个由 (N) 个整数组成的序列 (A),你需要应用 (M) 个操作:

    • (I) (p) (x)(p) 处插入插入一个元素 (x)
    • (D) (p) 删除 (p) 处的一个元素
    • (R) (p) (x) 修改 (p) 处元素的值为 (x)
    • (Q) (l) (r) 查询一个区间 ([l, r]) 的最大子段和

    思路

    平衡树呗,记得push up一下刚更新的节点就好啦。

    此处给出两个版本:

    • Splay版

    • FHQ Treap版

    请自行选择食用QwQ

    code1: (Splay)

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 200010
    #define inf 2147483647
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0') {if (ch == '-') f = -f; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    inline void write(int x){
        if (x < 0) putchar('-'), x = -x;
        if (x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    vector<int> ljt;
    struct tree{
        int ch[2], sze, fa;
        ll w, sum, lsum, rsum, msum;
        tree(int s, int f, int v, int su, int l, int r, int m)
            : sze(s), fa(f), w(v), sum(su), lsum(l), rsum(r), msum(m) { ch[0] = ch[1] = 0; }
        tree() : tree(0, 0, 0, 0, 0, 0, 0) {}
    };
    int n, m, tot, a[mn];
    tree z[mn];
    inline int newnode(int v = 0){
        int rt;
        if (ljt.empty())
            rt = ++tot;
        else
            rt = ljt.back(), ljt.pop_back();
        z[rt].fa = z[rt].ch[0] = z[rt].ch[1] = 0;
        z[rt].sze = 1;
        z[rt].w = z[rt].sum = v;
        z[rt].lsum = z[rt].rsum = z[rt].msum = max(v, 0);
        return rt;
    }
    inline void deletenode(int rt){
        z[rt].fa = z[rt].ch[0] = z[rt].ch[1] = z[rt].w = z[rt].sum = z[rt].msum = z[rt].lsum = z[rt].rsum = 0;
        z[rt].sze = 1;
        ljt.push_back(rt);
    }
    inline void update(int rt)
    {
        z[rt].sum = z[rt].w, z[rt].sze = 1;
        if (z[rt].ch[0])
            z[rt].sum += z[z[rt].ch[0]].sum, z[rt].sze += z[z[rt].ch[0]].sze;
        if (z[rt].ch[1])
            z[rt].sum += z[z[rt].ch[1]].sum, z[rt].sze += z[z[rt].ch[1]].sze;
        if (z[rt].ch[0] && z[rt].ch[1]) {
            z[rt].lsum = max(z[z[rt].ch[0]].lsum, z[z[rt].ch[0]].sum + z[rt].w + z[z[rt].ch[1]].lsum);
            z[rt].rsum = max(z[z[rt].ch[1]].rsum, z[z[rt].ch[1]].sum + z[rt].w + z[z[rt].ch[0]].rsum);
            z[rt].msum = max({z[z[rt].ch[0]].msum, z[z[rt].ch[1]].msum, z[z[rt].ch[0]].rsum + z[z[rt].ch[1]].lsum + z[rt].w});
        } else if (z[rt].ch[0]) {
            z[rt].lsum = max({z[z[rt].ch[0]].lsum, z[z[rt].ch[0]].sum + z[rt].w, 0ll});
            z[rt].rsum = max(z[z[rt].ch[0]].rsum + z[rt].w, 0ll);
            z[rt].msum = max(z[z[rt].ch[0]].msum, z[z[rt].ch[0]].rsum + z[rt].w);
        } else if (z[rt].ch[1]) {
            z[rt].lsum = max(z[z[rt].ch[1]].lsum + z[rt].w, 0ll);
            z[rt].rsum = max({z[z[rt].ch[1]].rsum, z[z[rt].ch[1]].sum + z[rt].w, 0ll});
            z[rt].msum = max(z[z[rt].ch[1]].msum, z[z[rt].ch[1]].lsum + z[rt].w);
        } else {
            z[rt].lsum = z[rt].rsum = max(z[rt].w, 0ll);
            z[rt].msum = z[rt].w;
        }
    }
    inline int iden(int rt) {
        return z[z[rt].fa].ch[0] == rt ? 0 : 1;
    }
    inline void connect(int x, int y, int son) {
        z[x].fa = y;
        z[y].ch[son] = x;
    }
    inline void rotate(int x) {
        int y = z[x].fa;
        int moot = z[y].fa;
        int yson = iden(x);
        int mootson = iden(y);
        int B = z[x].ch[yson ^ 1];
        connect(B, y, yson), connect(y, x, yson ^ 1), connect(x, moot, mootson);
        update(y), update(x);
    }
    inline void splay(int x, int &k) {
        if (x == k)
            return;
        int p = z[k].fa;
        while (z[x].fa != p) {
            int y = z[x].fa;
            if (z[y].fa != p)
                rotate(iden(y) ^ iden(x) ? x : y);
            rotate(x);
        }
        k = x;
    }
    inline int findkth(int rt, int k) {
        while (1119) {
            if (z[rt].ch[0] && k <= z[z[rt].ch[0]].sze)
                rt = z[rt].ch[0];
            else {
                if (z[rt].ch[0])
                    k -= z[z[rt].ch[0]].sze;
                if (!--k)
                    return rt;
                rt = z[rt].ch[1];
            }
        }
    }
    inline void insert(int &rt, int p, int v) {
        int x = findkth(rt, p);
        splay(x, rt);
        int y = findkth(rt, p + 1);
        int ooo = z[rt].ch[1];
        splay(y, ooo);
        z[y].ch[0] = newnode(v);
        z[z[y].ch[0]].fa = y;
        update(z[y].ch[0]), update(y), update(x);
    }
    inline void erase(int &rt, int p) {
        int y = findkth(rt, p);
        splay(y, rt);
        int x = findkth(rt, p + 1);
        int ooo = z[rt].ch[1];
        splay(x, ooo);
        int oo = z[x].ch[1];
        z[oo].fa = y;
        z[y].ch[1] = oo;
        deletenode(x);
        update(y);
    }
    inline int getRange(int &rt, int l, int r) {
        int x = findkth(rt, l);
        splay(x, rt);
        int y = findkth(rt, r + 2);
        int ooo = z[rt].ch[1];
        splay(y, ooo);
        return z[y].ch[0];
    }
    inline void modify(int &rt, int p, ll v) {
        int x = findkth(rt, p + 1);
        splay(x, rt);
        z[x].w = v;
        update(x);
    }
    inline ll query(int &rt, int l, int r) {
        int x = getRange(rt, l, r);
        return z[x].msum;
    }
    inline void build(int rt, int l, int r) {
        int m = (l + r) >> 1;
        z[rt].w = a[m];
        if (l <= m - 1) {
            z[rt].ch[0] = newnode();
            z[z[rt].ch[0]].fa = rt;
            build(z[rt].ch[0], l, m - 1);
        }
        if (m + 1 <= r) {
            z[rt].ch[1] = newnode();
            z[z[rt].ch[1]].fa = rt;
            build(z[rt].ch[1], m + 1, r);
        }
        update(rt);
    }
    int main()
    {
        n = read();
        go(i, 1, n, 1) a[i] = read();
        int rot = ++tot;
        build(rot, 0, n + 1);
        m = read();
        go(i, 1, m, 1)
        {
            char s;
            cin >> s;
            if (s == 'I') {
                int p = read(), v = read();
                insert(rot, p, v);
            } else if (s == 'D') {
                int p = read();
                erase(rot, p);
            } else if (s == 'R') {
                int p = read(), x = read();
                modify(rot, p, x);
            } else {
                int x = read(), y = read();
                printf("%lld
    ", query(rot, x, y));
            }
        }
        return 0;
    }
    

    code2: (FHQ Treap)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    using namespace std;
    #define go(i, j, n, k) for(int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
    #define mn 400010
    #define inf 1 << 30
    #define ll long long
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch > '9' || ch < '0') { if(ch == '-') f = -f; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    struct tree{
        int pri, ch[2], sze;
        ll x, sum, lsum, rsum, msum;
    } z[mn];
    inline void update(int rt)
    {
        z[rt].sum = z[rt].x, z[rt].sze = 1;
        if (z[rt].ch[0])
            z[rt].sum += z[z[rt].ch[0]].sum, z[rt].sze += z[z[rt].ch[0]].sze;
        if (z[rt].ch[1])
            z[rt].sum += z[z[rt].ch[1]].sum, z[rt].sze += z[z[rt].ch[1]].sze;
        if (z[rt].ch[0] && z[rt].ch[1]) {
            z[rt].lsum = max(z[z[rt].ch[0]].lsum, z[z[rt].ch[0]].sum + z[rt].x + z[z[rt].ch[1]].lsum);
            z[rt].rsum = max(z[z[rt].ch[1]].rsum, z[z[rt].ch[1]].sum + z[rt].x + z[z[rt].ch[0]].rsum);
            z[rt].msum = max(max(z[z[rt].ch[0]].msum, z[z[rt].ch[1]].msum), z[z[rt].ch[0]].rsum + z[z[rt].ch[1]].lsum + z[rt].x);
        } else if (z[rt].ch[0]) {
            z[rt].lsum = max(max(z[z[rt].ch[0]].lsum, z[z[rt].ch[0]].sum + z[rt].x), 0ll);
            z[rt].rsum = max(z[z[rt].ch[0]].rsum + z[rt].x, 0ll);
            z[rt].msum = max(z[z[rt].ch[0]].msum, z[z[rt].ch[0]].rsum + z[rt].x);
        } else if (z[rt].ch[1]) {
            z[rt].lsum = max(z[z[rt].ch[1]].lsum + z[rt].x, 0ll);
            z[rt].rsum = max(max(z[z[rt].ch[1]].rsum, z[z[rt].ch[1]].sum + z[rt].x), 0ll);
            z[rt].msum = max(z[z[rt].ch[1]].msum, z[z[rt].ch[1]].lsum + z[rt].x);
        } else {
            z[rt].lsum = z[rt].rsum = max(z[rt].x, 0ll);
            z[rt].msum = z[rt].x;
        }
    }
    int cnt;
    inline int newnode(int v = 0) {
        z[++cnt].x = z[cnt].msum = z[cnt].sum = v;
        z[cnt].lsum = z[cnt].rsum = max(v, 0);
        z[cnt].sze = 1;
        z[cnt].pri = rand();
        return cnt;
    }
    inline int merge(int x, int y) {
        if(!x || !y) return x + y;
        if(z[x].pri < z[y].pri) {
            z[x].ch[1] = merge(z[x].ch[1], y);
            update(x);
            return x;
        } else {
            z[y].ch[0] = merge(x, z[y].ch[0]);
            update(y);
            return y;
        }
    }
    inline void split(int rt, int k, int &x, int &y) {
        if(!rt) x = y = 0;
        else {
            if(k <= z[z[rt].ch[0]].sze) {
                y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
            } else {
                x = rt, split(z[rt].ch[1], k - z[z[rt].ch[0]].sze - 1, z[rt].ch[1], y);
            }
            update(rt);
        }
    }
    int n, m, xx, yy, zz, rot;
    inline void debug() {
        go(rt, 1, cnt, 1) {
            printf("%d: pri:%d, sze:%d, ch[0]:%d, ch[1]:%d, x:%d
    ", rt, z[rt].pri, z[rt].sze, z[rt].ch[0], z[rt].ch[1], z[rt].x);
        }
        printf("
    ");
    }
    int main() {
        srand((unsigned)time(NULL));
        n = read();
        go(i, 1, n, 1) {
            int x = read();
            split(rot, i, xx, yy);
            rot = merge(merge(xx, newnode(x)), yy);
        } 
        m = read();
        go(i, 1, m, 1) {
            char s;
            cin >> s;
            int x = read(), v;
            if(s == 'I') {
                v = read();
                split(rot, x - 1, xx, yy);	
                rot = merge(merge(xx, newnode(v)), yy);
                
            } else if(s == 'D') {
                split(rot, x, xx, zz);
                split(xx, x - 1, xx, yy);
                yy = merge(z[yy].ch[0], z[yy].ch[1]);
                rot = merge(merge(xx, yy), zz);
            } else if(s == 'R') {
                v = read();
                split(rot, x, xx, zz);
                split(xx, x - 1, xx, yy);
                z[yy].x = v;
                z[yy].sum = z[yy].msum = v;
                z[yy].lsum = z[yy].rsum = max(v, 0);
                rot = merge(merge(xx, yy), zz);
            } else if(s == 'Q') {
                v = read();
                split(rot, v, xx, zz);
                split(xx, x - 1, xx, yy);
                printf("%lld
    ", z[yy].msum);
                rot = merge(merge(xx, yy), zz);
            }
    //		debug();
        }
        return 0;
    }
    

    GSS7

    给定一棵树,有$ N (N ≤ 100000) $个节点,每一个节点都有一个权值 (x[i] (<= 10000))

    你需要执行 (Q (Q ≤ 100000)) 次操作:

    • (1) (a) (b) 查询 ((a,b)) 这条链上的最大子段和,可以为空(即输出(0)
    • (2) (a) (b) (c)((a,b)) 这条链上的所有点权变为 (c (|c| <= 10000))

    思路

    树链剖分套线段树维护区间最大子段和,基本没啥思路,直接套。不过代码细节较多。代码过长,引起极度不适。

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <ctime>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 100020
    #define inf 2147483647
    #define ll long long
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline void write(int x){
        if (x < 0)putchar('-'),x = -x;
        if (x > 9)write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    int n, m, r;
    struct tree{
        int sum, lsum, rsum, msum;
        tree() { sum = lsum = rsum = msum = 0; }
    };
    int dep[mn], sze[mn], son[mn], fa[mn], id[mn], top[mn], b[mn];
    int cnt;
    // Array -------------------------------------------------------------------
    struct SegmentTree{
        tree z[mn << 2];
        int col[mn << 2];
        int cd[mn << 2];
        inline void update(int rt){
            z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
            z[rt].lsum = max(z[rt << 1].lsum, z[rt << 1 | 1].lsum + z[rt << 1].sum);
            z[rt].rsum = max(z[rt << 1 | 1].rsum, z[rt << 1].rsum + z[rt << 1 | 1].sum);
            z[rt].msum = max({z[rt << 1].msum, z[rt << 1 | 1].msum, z[rt << 1].rsum + z[rt << 1 | 1].lsum});
        }
        inline tree operation(tree a,tree b){
            tree res;
            res.sum = a.sum + b.sum;
            res.lsum = max(a.lsum, a.sum + b.lsum);
            res.rsum = max(b.rsum, b.sum + a.rsum);
            res.msum = max({a.msum, b.msum, a.rsum + b.lsum});
            return res;
        }
        inline void push_col(int l,int r,int rt){
            if(cd[rt]) {
                int m = (l + r) >> 1;
                cd[rt << 1] = cd[rt << 1 | 1] = 1;
                col[rt << 1] = col[rt << 1 | 1] = col[rt];
                z[rt << 1].sum = (m - l + 1) * col[rt];
                z[rt << 1 | 1].sum = (r - m) * col[rt];
                z[rt << 1].lsum = z[rt << 1].rsum = z[rt << 1].msum = max(z[rt << 1].sum, 0);
                z[rt << 1 | 1].lsum = z[rt << 1 | 1].rsum = z[rt << 1 | 1].msum = max(z[rt << 1 | 1].sum, 0);
                cd[rt] = 0;
            }
        }
        inline void build(int l,int r,int rt){
            if(l==r){
                z[rt].sum = b[l];
                z[rt].lsum = z[rt].rsum = z[rt].msum = max(z[rt].sum, 0);
                return;
            }
            int m = (l + r) >> 1;
            build(lson);
            build(rson);
            update(rt);
        }
        inline void modify(int l,int r,int rt,int nowl,int nowr,int v){
            if(nowl<=l && r<=nowr){
                col[rt] = v;
                cd[rt] = 1;
                z[rt].sum = (r - l + 1) * v;
                z[rt].lsum = z[rt].rsum = z[rt].msum = max(z[rt].sum, 0);
                return;
            }
            int m = (l + r) >> 1;
            push_col(bson);
            if(nowl<=m)
                modify(lson, nowl, nowr, v);
            if(m<nowr)
                modify(rson, nowl, nowr, v);
            update(rt);
        }
        inline tree query(int l,int r,int rt,int nowl,int nowr){
            if(nowl<=l && r<=nowr){
                return z[rt];
            }
            int m = (l + r) >> 1;
            push_col(bson);
            if(nowl<=m){
                if(m<nowr)
                    return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
                else
                    return query(lson, nowl, nowr);
            }else{
                return query(rson, nowl, nowr);
            }
        }
    } tr;
    // Line Segment Tree ------------------------------------------------
    struct edge{
        int v, nxt;
    } e[mn << 1];
    int h[mn], w[mn], p;
    inline void add(int a,int b){
        e[++p].nxt = h[a];
        h[a] = p;
        e[p].v = b;
    }
    // Adjacency List ---------------------------------------------------------------
    void dfs1(int x,int f,int deep){
        dep[x] = deep;
        sze[x] = 1;
        fa[x] = f;
        int maxson = -1;
        rep(i,x){
            int v = e[i].v;
            if(v == f)
                continue;
            dfs1(v, x, deep + 1);
            sze[x] += sze[v];
            if (maxson < sze[v])
                maxson = sze[v], son[x] = v;
        }
    }
    void dfs2(int x,int topf){
        id[x] = ++cnt;
        b[id[x]] = w[x];
        top[x] = topf;
        if(!son[x])
            return;
        dfs2(son[x], topf);
        rep(i,x){
            int v = e[i].v;
            if(v==fa[x] || v==son[x])
                continue;
            dfs2(v, v);
        }
    }
    // DFS ----------------------------------------------------------------
    /*
    inline void modifyTree(int x,int y,int v){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]])
                swap(x, y);
            tr.modify(root, id[top[x]], id[x], v);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y])
            swap(x, y);
        tr.modify(root, id[x], id[y], v);
    }
    */
    inline void modifyTree(int x,int y,int v){
        while(top[x] != top[y]){
            if(dep[top[x]] > dep[top[y]]){
                tr.modify(root, id[top[x]], id[x], v);
                x = fa[top[x]];
            }else{
                tr.modify(root, id[top[y]], id[y], v);
                y = fa[top[y]];
            }
        }
        if(dep[x] > dep[y])
            tr.modify(root, id[y], id[x], v);
        else
            tr.modify(root, id[x], id[y], v);
    }
    inline tree queryTree(int x,int y){
        tree lt, rt;
        while(top[x] != top[y]){
            if(dep[top[x]] > dep[top[y]]){
                tree get = tr.query(root, id[top[x]], id[x]);
                lt.msum = max({lt.msum, get.msum, lt.lsum + get.rsum});
                lt.lsum = max(lt.lsum + get.sum, get.lsum);
                lt.rsum = max(lt.rsum, get.rsum + lt.sum);
                lt.sum += get.sum;
                x = fa[top[x]];
            }else{
                tree get = tr.query(root, id[top[y]], id[y]);
                rt.msum = max({rt.msum, get.msum, rt.lsum + get.rsum});
                rt.lsum = max(rt.lsum + get.sum, get.lsum);
                rt.rsum = max(rt.rsum, rt.sum + get.rsum);
                rt.sum += get.sum;
                y = fa[top[y]];
            }
            //cout << "lalala
    ";
        }
        //printf("%d %d %d %d
    %d %d %d %d
    ", lt.lsum, lt.rsum, lt.sum, lt.msum, rt.lsum, rt.rsum, rt.sum, rt.msum);
        if(dep[x] < dep[y]){
            tree get = tr.query(root, id[x], id[y]);
            rt.msum = max({rt.msum, get.msum, rt.lsum + get.rsum});
            rt.lsum = max(get.lsum, get.sum + rt.lsum);
            rt.rsum = max(rt.rsum, rt.sum + get.rsum);
            rt.sum += get.sum;
        }else{
            tree get = tr.query(root, id[y], id[x]);
            lt.msum = max({lt.msum, get.msum, lt.lsum + get.rsum});
            lt.lsum = max(get.lsum, get.sum + lt.lsum);
            lt.rsum = max(lt.rsum, lt.sum + get.rsum);
            lt.sum += get.sum;
        }
        //cout << "lalala
    ";
        tree res;
        res.sum = lt.sum + rt.sum;
        res.lsum = max(lt.lsum, lt.sum + rt.rsum);
        res.rsum = max(rt.lsum, rt.sum + lt.rsum);
        res.msum = max({lt.msum, rt.msum, lt.lsum + rt.lsum});
        return res;
    }
    // Modify and Query ------------------------------------------------------
    int main()
    {
        n = read();
        r = 1;
        go(i, 1, n, 1) w[i] = read();
        go(i, 1, n - 1, 1){
            int x = read(), y = read();
            add(x, y), add(y, x);
        }
        dfs1(r, 0, 1);
        dfs2(r, r);
        tr.build(root);
        m = read();
        go(i, 1, m, 1){
            int s = read(), x = read(), y = read();
            if(s==2){
                int v = read();
                modifyTree(x, y, v);
            }else{
                cout << queryTree(x, y).msum << "
    ";
                //cout << "lalala
    ";
            }
        }
        return 0;
    }
    
    

    GSS8

    给你一个序列,(A[0], A[1]...A[N - 1].) ((0 le A[i] lt 2^{32}))

    你需要支持 Q 次操作

    • (I) (pos) (val) 插入一个数字在第 (pos) 个位置之前,(0 le val lt 2^{32})
      , 如果(pos=current) (length),那么你需要将这个数字放到序列末尾
    • D pos 删除第 (pos) 个元素
    • R pos val 将第 (pos) 个元素变为(val(0 le val lt 2^{32}))
    • Q l r k 询问((sumlimits_{i=l}^{r} A[i] * (i - l + 1) ^ k) mod 2^{32}),保证(0 le k le 10)

    思路

    对于每一个 k 都维护一个答案。

    如果 k = 0, 就是区间和,如果 k = 1,我们可以用这样的式子写:

    z[rt].ans[1] = z[z[rt].ch[0]].ans[1] + z[z[rt].ch[1]].ans[1] + (z[z[rt].ch[1]].sum * z[z[rt].ch[0]].sze)
    

    但如果我们考虑 k > 1,我们仍考虑左右合并,但不是左边不动的,我们把表达式化简一下。(以下计算过程参考 hzk_cpp 巨佬的 计算过程)

    (A[i](i - l + 1)^k)

    = (A[i]((mid - l + 1) + (i - mid))^k)

    (x = i - l + 1),实际就是左区间的长度,设 $ rs.ans[j] $ 作为 ([min + 1, r])(k = j) 的答案。

    = (A[i](x + i - mid)^k)

    由二项式定理得

    = (A[i]sum_{j=0}^kC_k^jx^{k-j}(i - mid)^j)

    我们右边所有的值加起来,得:

    = (sum_{i=mid+1}^rA[i]sum_{j=0}^kC_k^jx^{k-j}(i - mid)^j)

    = (sum_{i=mid+1}^rsum_{j=0}^kA[i]C_k^jx^{k-j}(i - mid)^j)

    = (sum_{j=0}^kC_k^jx^{k-j}rs.ans[j])

    这个式子直接可以暴力在update函数中直接更新,毕竟 (k <= 10),不伤身体。

    目前只有Splay版,FHQ Treap版正在调。

    code:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <ctime>
    #include <iostream>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define mn 200010
    #define inf 2147483647
    #define ll unsigned int
    inline ll read(){
        ll x = 0; char ch = getchar(); 
        while (ch > '9' || ch < '0') { ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return x;
    }
    inline void write(int x){
        if (x < 0) putchar('-'), x = -x;
        if (x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
    //This is AC head above...
    vector<int> ljt;
    struct tree{
        int ch[2], sze, fa;
        ll w, ans[11];
        tree(int s, int f, int v)
            : sze(s), fa(f), w(v) { ch[0] = ch[1] = 0; 
                go(i, 0, 10, 1) ans[i] = 0; }
        tree() : tree(0, 0, 0) {}
    };
    int n, m, tot;
    ll a[mn];
    tree z[mn];
    ll po[mn], C[11][11];
    inline int newnode(int v = 0){
        int rt;
        if (ljt.empty())
            rt = ++tot;
        else
            rt = ljt.back(), ljt.pop_back();
        z[rt].fa = z[rt].ch[0] = z[rt].ch[1] = 0;
        z[rt].sze = 1;
        z[rt].w = v;
        return rt;
    }
    inline void deletenode(int rt){
        z[rt].fa = z[rt].ch[0] = z[rt].ch[1] = z[rt].w = 0;
        go(i, 0, 10, 1) z[rt].ans[i] = 0;
        z[rt].sze = 1;
        ljt.push_back(rt);
    }
    inline void update(int rt) {
        z[rt].sze = 1;
        if(z[rt].ch[0]) z[rt].sze += z[z[rt].ch[0]].sze;
        if(z[rt].ch[1]) z[rt].sze += z[z[rt].ch[1]].sze;
        po[0] = 1ll;
        go(i, 1, 10, 1)
            po[i] = po[i - 1] * (z[z[rt].ch[0]].sze + 1);
        go(i, 0, 10, 1) {
            z[rt].ans[i] = z[z[rt].ch[0]].ans[i] + z[rt].w * po[i];
            go(j, 0, i, 1)
                z[rt].ans[i] = z[rt].ans[i] + z[z[rt].ch[1]].ans[j] * po[i - j] * C[i][j];
        }
    }
    inline int iden(int rt) {
        return z[z[rt].fa].ch[0] == rt ? 0 : 1;
    }
    inline void connect(int x, int y, int son) {
        z[x].fa = y;
        z[y].ch[son] = x;
    }
    inline void rotate(int x) {
        int y = z[x].fa;
        int moot = z[y].fa;
        int yson = iden(x);
        int mootson = iden(y);
        int B = z[x].ch[yson ^ 1];
        connect(B, y, yson), connect(y, x, yson ^ 1), connect(x, moot, mootson);
        update(y), update(x);
    }
    inline void splay(int x, int &k) {
        if (x == k)
            return;
        int p = z[k].fa;
        while (z[x].fa != p) {
            int y = z[x].fa;
            if (z[y].fa != p)
                rotate(iden(y) ^ iden(x) ? x : y);
            rotate(x);
        }
        k = x;
    }
    inline int findkth(int rt, int k) {
        while (1119) {
            if (z[rt].ch[0] && k <= z[z[rt].ch[0]].sze)
                rt = z[rt].ch[0];
            else {
                if (z[rt].ch[0])
                    k -= z[z[rt].ch[0]].sze;
                if (!--k)
                    return rt;
                rt = z[rt].ch[1];
            }
        }
    }
    inline void insert(int &rt, int p, int v) {
        int x = findkth(rt, p);
        splay(x, rt);
        int y = findkth(rt, p + 1);
        int ooo = z[rt].ch[1];
        splay(y, ooo);
        z[y].ch[0] = newnode(v);
        z[z[y].ch[0]].fa = y;
        update(z[y].ch[0]), update(y), update(x);
    }
    inline void erase(int &rt, int p) {
        int y = findkth(rt, p);
        splay(y, rt);
        int x = findkth(rt, p + 1);
        int ooo = z[rt].ch[1];
        splay(x, ooo);
        int oo = z[x].ch[1];
        z[oo].fa = y;
        z[y].ch[1] = oo;
        deletenode(x);
        update(y);
    }
    inline int getRange(int &rt, int l, int r) {
        int x = findkth(rt, l);
        splay(x, rt);
        int y = findkth(rt, r + 2);
        int ooo = z[rt].ch[1];
        splay(y, ooo);
        return z[y].ch[0];
    }
    inline void modify(int &rt, int p, ll v) {
        int x = findkth(rt, p + 1);
        splay(x, rt);
        z[x].w = v;
        update(x);
    }
    inline ll query(int &rt, int l, int r, int k) {
        int x = getRange(rt, l, r);
        return z[x].ans[k];
    }
    inline void build(int rt, int l, int r) {
        int m = (l + r) >> 1;
        z[rt].w = a[m];
        if (l <= m - 1) {
            z[rt].ch[0] = newnode();
            z[z[rt].ch[0]].fa = rt;
            build(z[rt].ch[0], l, m - 1);
        }
        if (m + 1 <= r) {
            z[rt].ch[1] = newnode();
            z[z[rt].ch[1]].fa = rt;
            build(z[rt].ch[1], m + 1, r);
        }
        update(rt);
    }
    inline void init() 
    {
        go(i, 0, 10, 1) C[i][0] = C[i][i] = 1;
        go(i, 1, 10, 1) 
            go(j, 1, i, 1)
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
    //    go(i, 0, 10, 1) 
    //        go(j, 0, 10, 1) 
    //            printf("%5d%c", C[i][j], (j == 10) ? '
    ' : ' ');
    
    }
    int main()
    {
        init();
        n = read();
        go(i, 1, n, 1) a[i] = read();
        int rot = ++tot;
        build(rot, 0, n + 1);
        m = read();
        go(i, 1, m, 1)
        {
            char s;
            cin >> s;
            if (s == 'I') {
                int p = read() + 1, v = read();
                insert(rot, p, v);
            } else if (s == 'D') {
                int p = read() + 1;
                erase(rot, p);
            } else if (s == 'R') {
                int p = read() + 1, x = read();
                modify(rot, p, x);
            } else {
                int x = read() + 1, y = read() + 1, z = read();
                printf("%lld
    ", query(rot, x, y, z));
            }
        }
        return 0;
    }
    
    

    所有系列题目完成于 2019 / 3 / 25 23 : 02 : 29

  • 相关阅读:
    产品思维和用户思维
    IT界是丽春院?
    凡事要讲究方式方法
    一个比较差的接口定义
    软件开发中的官话和土话
    Frida之app逆向hook,动态插装
    Airtext远程控制多台手机
    linux下使用uwsgi部署flask写的接口遇到的坑
    软件质量管理(六)- 无有规矩不成方圆
    软件质量管理(五)- 质量优异的产品离不开一支优秀的团队
  • 原文地址:https://www.cnblogs.com/yizimi/p/10597818.html
Copyright © 2020-2023  润新知