Codeforces 815D Karen and Cards 线段树 || 容斥 (看题解)
刚开始想的是容斥, 但是感觉不太好容斥, 然后就gun去看题解了。。
我们考虑枚举 a , n张排分成两种 >= a 和 < a,然后我们把后两维看成平面上的点, 考虑哪些点会受到
限制, 对于 >= a 的卡片来说, 受限制区域为整个区域减去右上角矩形, 对于 < a的卡片来说, 受限制区域为
左下角矩形, 定义f(b)为第二位为 b 使 c 受限制的最大值, 首先发现 f 函数是单调的, 一张卡片从 < a 转变到 >= a很好修改,
所以我们从大到小枚举 a 用线段树去统计在答案。
容斥的话可以看这个。。
https://codeforces.com/contest/815/submission/27860187
感觉有点巧妙。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 5e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} int n, p, q, r; int a[N], b[N], c[N]; int id[N], limit[N]; LL ans; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 struct segmentTree { LL sum[N << 2]; int lazy[N << 2], mn[N << 2], mx[N << 2]; inline void pull(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]); } inline void push(int rt, int l, int r) { if(~lazy[rt]) { int mid = l + r >> 1; sum[rt << 1] = 1LL * (mid - l + 1) * lazy[rt]; sum[rt << 1 | 1] = 1LL * (r - mid) * lazy[rt]; lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt]; mx[rt << 1] = mn[rt << 1] = lazy[rt]; mx[rt << 1 | 1] = mn[rt << 1 | 1] = lazy[rt]; lazy[rt] = -1; } } void build(int l, int r, int rt) { lazy[rt] = -1; if(l == r) { sum[rt] = limit[l]; mx[rt] = limit[l]; mn[rt] = limit[l]; return; } int mid = l + r >> 1; build(lson); build(rson); pull(rt); } void update(int L, int R, int val, int l, int r, int rt) { if(R < l || r < L || R < L) return; if(mn[rt] >= val) return; if(L <= l && r <= R && mx[rt] <= val) { sum[rt] = 1LL * (r - l + 1) * val; mx[rt] = val; mn[rt] = val; lazy[rt] = val; return; } if(l == r) return; push(rt, l, r); int mid = l + r >> 1; update(L, R, val, lson); update(L, R, val, rson); pull(rt); } } Tree; int main() { scanf("%d%d%d%d", &n, &p, &q, &r); for(int i = 1; i <= n; i++) { scanf("%d%d%d", &a[i], &b[i], &c[i]); id[i] = i; } sort(id + 1, id + 1 + n, [&](int x, int y) { return a[x] > a[y]; }); for(int i = 1; i <= n; i++) chkmax(limit[b[i]], c[i]); for(int i = q; i >= 1; i--) chkmax(limit[i], limit[i + 1]); Tree.build(1, q, 1); for(int i = p, j = 1; i >= 1; i--) { while(j <= n && a[id[j]] >= i) { Tree.update(1, b[id[j]], r, 1, q, 1); Tree.update(b[id[j]] + 1, q, c[id[j]], 1, q, 1); j++; } ans += 1LL * q * r - Tree.sum[1]; } printf("%lld\n", ans); return 0; } /* */