E. Divide Square (树状数组,扫描线,思维)
题目:传送门
题意
在左下角为(0, 0),右上角为 (1e6, 1e6) 的正方形中,有 n 条平行于 x 轴的线段和 m 条平行于 y 轴的线段,保证每条线段至少与正方形的一条边相交,且保证不存在两条线段在同一条线上,问你这些线段将正方形分成了几块.
思路
有两种情况,会增加一块:
1.当线段与正方形的两条边相交时
2.当两条线段相交时
所以问题转化为求线段的交点个数,用扫描线+树状数组即可
#include <bits/stdc++.h> #define LL long long #define ULL unsigned long long #define UI unsigned int #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF 0x3f3f3f3f #define inf LLONG_MAX #define PI acos(-1) #define fir first #define sec second #define lb(x) ((x) & (-(x))) #define dbg(x) cout<<#x<<" = "<<x<<endl; using namespace std; const int N = 1e6 + 5; int n, m; struct note { int y, l, r; }a[N]; struct node { int x, l, r; }b[N]; vector < pair < int, int > > A[N], x[N]; int t[N]; void add(int pos, int x) { for(int i = pos; i < N; i += lb(i)) { t[i] += x; } } int query(int pos) { int ans = 0; for(int i = pos; i; i -= lb(i)) { ans += t[i]; } return ans; } void solve() { scanf("%d %d", &n, &m); LL ans = 1LL; rep(i, 1, n) { scanf("%d %d %d", &a[i].y, &a[i].l, &a[i].r); A[a[i].l].pb(make(a[i].y, 1)); A[a[i].r + 1].pb(make(a[i].y, -1)); if(a[i].l == 0 && a[i].r == 1000000) ans++; } rep(i, 1, m) { scanf("%d %d %d", &b[i].x, &b[i].l, &b[i].r); x[b[i].x].pb(make(b[i].l, b[i].r)); if(b[i].l == 0 && b[i].r == 1000000) ans++; } rep(i, 0, 1000000) { for(auto v : A[i]) add(v.fir, v.sec); for(auto v : x[i]) { int tmp1 = query(v.sec); int tmp2 = v.fir == 0 ? 0 : query(v.fir - 1); ans += tmp1 - tmp2; } } printf("%lld\n", ans); } int main() { // int _; scanf("%d", &_); // while(_--) solve(); solve(); return 0; }
一步一步,永不停息