已知luogu是按照实际使用计算空间的,下面这份代码最大的几个点只用了 3×106 左右个线段树节点,但是所有测试点的内存用量都基本达到了静态内存总和,差的那一点大概是链表部分。我怀疑是哪里访问越界,但使用 Ubsan 或者直接将线段树节点开到 4×106 也没有任何问题,不过所有测试点内存仍然跑满,我确实找不到问题,求各位大佬帮忙看看
格式化后代码
#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define Rep(i, a, b) for (int i = a; i <= b; ++i)
#define Dwn(i, a, b) for (int i = a; i >= b; --i)
#define pii pair<int, int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn = 1e6 + 10, B = 1e6;
struct V1 {
int val, pre, nxt;
} V[maxn * 2];
int tot;
struct List {
int Head, Tail;
void Init() {
Head = ++tot, Tail = ++tot;
V[Head].nxt = Tail, V[Tail].pre = Head;
}
void Push_back(int x) {
++tot;
V[tot].val = x;
V[tot].pre = V[Tail].pre, V[V[tot].pre].nxt = tot, V[tot].nxt = Tail, V[Tail].pre = tot;
}
void Merge(List &A) {
V[V[Tail].pre].nxt = V[A.Head].nxt;
V[V[A.Head].nxt].pre = V[Tail].pre;
Tail = A.Tail;
}
void Pop_back() {
int p = V[V[Tail].pre].pre;
V[p].nxt = Tail, V[Tail].pre = p;
}
int Back() { return V[V[Tail].pre].val; }
} L[maxn];
int n, q;
pii operator-(const pii &x, const pii &y) { return pii(x.fir, x.sec - y.sec); }
pii operator+(const pii &x, const pii &y) {
if (x.fir == y.fir)
return pii(x.fir, x.sec + y.sec);
return x.sec > y.sec ? x - y : y - x;
}
int root[maxn];
struct Seg {
#define LCH tr[rt].lch
#define RCH tr[rt].rch
struct Tree {
int lch, rch, siz;
pii val;
} tr[maxn * 30];
int tot;
void Pushup(int rt) {
tr[rt].val = (tr[LCH].val + tr[RCH].val), tr[rt].siz = (tr[LCH].siz + tr[RCH].siz);
}
void Insert(int &rt, int l, int r, int x, int w) {
if (!rt)
rt = ++tot;
if (l == r)
return tr[rt].val.fir = x, tr[rt].val.sec += w, tr[rt].siz += w, void();
int mid = (l + r) >> 1;
if (x <= mid)
Insert(LCH, l, mid, x, w);
else
Insert(RCH, mid + 1, r, x, w);
Pushup(rt);
}
int Query(int rt, int l, int r, int x) {
if (!rt)
return 0;
if (l == r)
return tr[rt].val.sec;
int mid = (l + r) >> 1;
if (x <= mid)
return Query(LCH, l, mid, x);
else
return Query(RCH, mid + 1, r, x);
}
int Merge(int x, int y, int l, int r) {
if (!x || !y)
return x | y;
if (l == r)
return tr[x].siz += tr[y].siz, tr[x].val.sec = tr[x].siz, x;
int mid = (l + r) >> 1;
tr[x].lch = Merge(tr[x].lch, tr[y].lch, l, mid);
tr[x].rch = Merge(tr[x].rch, tr[y].rch, mid + 1, r);
Pushup(x);
return x;
}
} T;
int a[maxn];
void solve() {
cin >> n >> q;
Rep(i, 1, n) {
int len, x;
cin >> len;
L[i].Init();
Rep(j, 1, len) cin >> x, L[i].Push_back(x), T.Insert(root[i], 1, B, x, 1);
}
while (q--) {
int opt;
cin >> opt;
if (opt == 1) {
int x, y;
cin >> x >> y;
L[x].Push_back(y);
T.Insert(root[x], 1, B, y, 1);
}
if (opt == 2) {
int x;
cin >> x;
T.Insert(root[x], 1, B, L[x].Back(), -1);
L[x].Pop_back();
}
if (opt == 3) {
int m;
cin >> m;
pii val;
ll sum = 0, csum = 0;
Rep(i, 1, m) cin >> a[i], val = (val + T.tr[root[a[i]]].val), sum += T.tr[root[a[i]]].siz;
Rep(i, 1, m) csum += T.Query(root[a[i]], 1, B, val.fir);
if ((csum << 1) > sum)
cout << val.fir << "\n";
else
cout << -1 << "\n";
}
if (opt == 4) {
int x, y, w;
cin >> x >> y >> w;
L[x].Merge(L[y]);
L[w] = L[x];
root[w] = T.Merge(root[x], root[y], 1, B);
}
}
cerr << tot << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
return solve(), 0;
}