【bzoj 3615】MSS 分块 线段树的合并和拆分

二维坐标上有n个点,每维坐标互不相同。初始时每个点为一个独立的集合,要求维护:

合并两个集合

将集合id某一维以v为界拆分为两个集合

将集合x的数都加d

询问一个集合的sum,max,min


考虑按x坐标分块,对每个集合,每块建一个线段树。

/**************************************************************
    Problem: 3615
    User: hzt1
    Language: C++
    Result: Accepted
    Time:18824 ms
    Memory:375412 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
#define u t[x]
#define o t[y]
#define Tx t[tx]
#define Ty t[ty]
#define Lc t[ u.lc ]
#define Rc t[ u.rc ]
using namespace std;
typedef long long LL;
const int N = 51000, M = 110; const LL inf = 1LL << 60;
struct node { int x, y, z, n; } p[N];
struct Seg_node { int lc, rc, x, sz; LL sum, mx, mn, lz; } t[N * M];
int n, ro[N * 4][M], cz, Q, qx, Bz, X[N], l0[N], r0[N], q, B, Y[N], bin[N * M], bz; char Type[8]; // In[N * M]
LL ans, mx, mn;
// long long ...
bool cmpx(node a, node b) { return a.x < b.x; }
bool cmpy(node a, node b) { return a.y < b.y; }
void Del(int x) { u.mx = -inf, u.mn = inf, u.lc = u.rc = u.x = u.sz = u.lz = u.sum = 0; bin[++ bz] = x; }
void PD(int x) {
    if (!x) return ;
    u.sum += u.lz * u.sz, Lc.lz += u.lz, Rc.lz += u.lz; u.mn += u.lz, u.mx += u.lz; u.lz = 0;
}
void Upd(int x) { u.sz = Lc.sz + Rc.sz, u.sum = Lc.sum + Rc.sum, u.mx = max(Lc.mx, Rc.mx), u.mn = min(Lc.mn, Rc.mn); }
void Build(int &x, int l, int r) {
    x = bin[bz --], u.sz = 1, u.sum = u.mx = u.mn = p[q].z; // In[x]
    if (l == r) { u.x = p[q].x; return ; }
    int mid = l + r >> 1;
    if (p[q].y <= mid) Build(u.lc, l, mid); else Build(u.rc, mid + 1, r);
}
void Split(int x, int &tx, int &ty, int l, int r) {
    if (!x) return ; PD(x);
    if (Y[r] <= q) { tx = x; return ; }
    if (Y[l] > q) { ty = x; return ; }
    tx = bin[bz --], ty = bin[bz --];
    int mid = l + r >> 1;
    Split(u.lc, Tx.lc, Ty.lc, l, mid), Split(u.rc, Tx.rc, Ty.rc, mid + 1, r);
    Del(x); Upd(tx), Upd(ty);
}
int Merge(int x, int y) {
    PD(x), PD(y);
    if (!x || !y) return x + y;
    u.lc = Merge(u.lc, o.lc), u.rc = Merge(u.rc, o.rc);
    Del(y); Upd(x); return x;
}
void Sx(int x, int &tx, int &ty, int l, int r) {
    if (!x) return ; PD(x);
    if (l == r) { if (u.x <= q) tx = x; else ty = x; return ; }
    int mid = l + r >> 1, lx, rx, ly, ry;
    lx = rx = ly = ry = 0;
    if (u.lc) Sx(u.lc, lx, ly, l, mid);
    if (u.rc) Sx(u.rc, rx, ry, mid + 1, r);
    Del(x);
    if (lx || rx) tx = bin[bz --], Tx.lc = lx, Tx.rc = rx, Upd(tx);
    if (ly || ry) ty = bin[bz --], Ty.lc = ly, Ty.rc = ry, Upd(ty);
}
int main()
{
    scanf ("%d", &n), cz = n;
    Rep(i, 1, N * M - 10) bin[i] = i, Del(i);
    Del(0); bz = N * M - 10;
    Rep(i, 1, n) {
        scanf ("%d%d%d", &p[i].x, &p[i].y, &p[i].z); p[i].n = i;
    }
    sort(p + 1, p + n + 1, cmpy);
    Rep(i, 1, n) Y[i] = p[i].y, p[i].y = i;
    sort(p + 1, p + n + 1, cmpx);
    // B = sqrt(n) + 1;
    B = min(n, 600);
    for (int i = 1; i <= n; i += B) {
        Bz ++, l0[Bz] = i, r0[Bz] = min(i + B - 1, n);
        Rep(j, i, r0[Bz]) {
            X[j] = p[j].x;
            q = j, Build(ro[ p[j].n ][Bz], 1, n);
        }
    }
    // t[0].mn = inf;
    scanf ("%d", &Q);
    while (Q --) {
        scanf ("%s", Type);
        int x, y, d, v, z;
        if (Type[0] == 'M') {
            scanf ("%d%d", &x, &y);
            Rep(i, 1, Bz) ro[x][i] = Merge(ro[x][i], ro[y][i]), ro[y][i] = 0;
            // puts("fin");
        } else if (Type[0] == 'S') {
            scanf ("%d%d%d", &x, &d, &v);
            if (!d) {
                Rep(i, 1, Bz) {
                    if (v >= X[ r0[i] ]) ro[cz + 1][i] = ro[x][i];
                    else if (v < X[ l0[i] ]) ro[cz + 2][i] = ro[x][i];
                    else {
                        // nk += t[ ro[x][i] ].sz;
                        q = v, Sx(ro[x][i], ro[cz + 1][i], ro[cz + 2][i], 1, n);
                    }
                    ro[x][i] = 0;
                }
            } else {
                q = v; Rep(i, 1, Bz) Split(ro[x][i], ro[cz + 1][i], ro[cz + 2][i], 1, n), ro[x][i] = 0;
            }
            cz += 2;
        } else if (Type[0] == 'Q') {
            scanf ("%d", &qx);
            ans = 0, mx = -inf, mn = inf;
            Rep(i, 1, Bz) {
                x = ro[qx][i];
                if (x) ans += u.sum, mx = max(mx, u.mx), mn = min(mn, u.mn);
            }
            printf("%lld %lld %lld\n", mx, mn, ans);
        } else {
            scanf ("%d%d", &qx, &z);
            Rep(i, 1, Bz) {
                x = ro[qx][i]; if (x) u.lz += z, PD(x);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值