用两种线段树思路打开双元贡献计算
(1) tree[c][u].sorted_w.resize(lw.size() + rw.size());
merge(lw.begin(), lw.end(), rw.begin(), rw.end(), tree[c][u].sorted_w.begin());
#include <bits/stdc++.h>
using namespace std;
#define int long long // 使用64位整型防止溢出
const int MOD = 1e9+7;
const int N = 1e5+5;
struct Rect {
int l, w, c;
bool operator<(const Rect& o) const { return l < o.l; }
};
struct Node {
int l, r;
vector<int> sorted_w;
} tree[3][N*4];
vector<Rect> colors[3];
vector<int> sorted_l[3];
void build(int c, int u, int l, int r) {
tree[c][u].l = l;
tree[c][u].r = r;
if(l == r) {
tree[c][u].sorted_w = {colors[c][l].w};
return;
}
int mid = (l + r) >> 1;
build(c, u<<1, l, mid);
build(c, u<<1|1, mid+1, r);
auto& lw = tree[c][u<<1].sorted_w;
auto& rw = tree[c][u<<1|1].sorted_w;
tree[c][u].sorted_w.resize(lw.size() + rw.size());
merge(lw.begin(), lw.end(), rw.begin(), rw.end(), tree[c][u].sorted_w.begin());
}
int query(int c, int u, int L, int R, int target_w) {
if(tree[c][u].r < L || tree[c][u].l > R) return 0;
if(L <= tree[c][u].l && tree[c][u].r <= R) {
auto& vec = tree[c][u].sorted_w;
return vec.end() - upper_bound(vec.begin(), vec.end(), target_w);
}
return query(c, u<<1, L, R, target_w) +
query(c, u<<1|1, L, R, target_w);
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
int n; cin >> n;
for(int i = 0; i < n; ++i) {
int l, w, c;
cin >> l >> w >> c;
colors[c].push_back({l, w, c});
}
for(int c = 0; c < 3; ++c) {
if(colors[c].empty()) continue;
sort(colors[c].begin(), colors[c].end());
sorted_l[c].reserve(colors[c].size());
for(auto& rect : colors[c]) {
sorted_l[c].push_back(rect.l);
}
build(c, 1, 0, colors[c].size()-1);
}
int ans = 0;
for(int cur_c = 0; cur_c < 3; ++cur_c) {
for(auto& rect : colors[cur_c]) {
for(int other_c = 0; other_c < 3; ++other_c) {
if(other_c == cur_c) continue;
if(colors[other_c].empty()) continue;
auto& sl = sorted_l[other_c];
int k = lower_bound(sl.begin(), sl.end(), rect.l) - sl.begin();
if(k == 0) continue;
ans += query(other_c, 1, 0, k-1, rect.w);
ans %= MOD;
}
}
}
cout << ans % MOD << "\n";
}
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls(u) (u<<1)
#define rs(u) (u<<1|1)
typedef pair<int,int> pii;
const int N=1e5+10, mod=1e9+7;
struct Node {
int l, r, sum;
} tr[N<<2][3];
short oth[3][2] = {{1,2}, {0,2}, {0,1}};
int n;
struct Rect {
int x, y, c;
bool operator<(const Rect& t) const { return x < t.x; }
} a[N];
void pushup(int c, int u) {
tr[u][c].sum = (tr[ls(u)][c].sum + tr[rs(u)][c].sum) % mod;
}
void update(int c, int u, int l, int r, int pos) {
if(tr[u][c].l == tr[u][c].r) {
tr[u][c].sum = (tr[u][c].sum + 1) % mod;
return;
}
int mid = (tr[u][c].l + tr[u][c].r) >> 1;
if(pos <= mid) {
if(!tr[ls(u)][c].sum) {
tr[ls(u)][c] = {tr[u][c].l, mid, 0};
}
update(c, ls(u), l, mid, pos);
} else {
if(!tr[rs(u)][c].sum) {
tr[rs(u)][c] = {mid+1, tr[u][c].r, 0};
}
update(c, rs(u), mid+1, r, pos);
}
pushup(c, u);
}
int query(int c, int u, int ql, int qr) {
if(tr[u][c].r < ql || tr[u][c].l > qr) return 0;
if(ql <= tr[u][c].l && tr[u][c].r <= qr) return tr[u][c].sum;
int res = 0;
if(tr[ls(u)][c].sum)
res += query(c, ls(u), ql, qr);
if(tr[rs(u)][c].sum)
res += query(c, rs(u), ql, qr);
return res % mod;
}
signed main() {
cin >> n;
for(int i=1; i<=n; i++) {
int x, y, c;
cin >> x >> y >> c;
a[i] = {x, y, c};
}
sort(a+1, a+1+n);
for(int c=0; c<3; c++)
tr[1][c] = {1, N-10, 0};
int ans = 0, cur = 1;
for(int i=1; i<=n; i++) {
int c = a[i].c, y = a[i].y;
ans = (ans + query(oth[c][0], 1, y+1, N-10)) % mod;
ans = (ans + query(oth[c][1], 1, y+1, N-10)) % mod;
if(i == n || a[i].x < a[i+1].x) {
for(; cur<=i; cur++) {
int cc = a[cur].c, yy = a[cur].y;
update(cc, 1, 1, N-10, yy);
}
}
}
cout << ans % mod << endl;
return 0;
}
男泵,树上差分叠加点