1 条题解
-
0
思路
对每个社团 ,取消它的摊位后,空闲格数等于
所以只需要统计:操场中完全没被覆盖的格子数 ,以及每个社团单独覆盖(只被它一个摊位覆盖)的格子数 。答案就是 ——这些格子原本被覆盖,取消该摊位后都会变为空闲。
用二维差分维护两个数组:
a[i][j]:覆盖 的摊位个数;b[i][j]:覆盖 的摊位编号之和。
对第 个矩形执行四次差分:
a的角上 ,b的角上 。做完二维前缀和后:a[i][j]==0:该格从未被覆盖,直接计入 ;a[i][j]==1:该格恰好被一个摊位覆盖,此时b[i][j]就是那个摊位的编号(求和里只有它一项),计入 ;a[i][j]>=2:取消任何一个摊位后该格仍被覆盖,与答案无关,不统计b。
注意只在
a[i][j]==1时读取b[i][j];覆盖数大于 时编号和可能恰好等于某个编号(例如 ),不能用它判断归属。最后对每个 输出 。
时间复杂度 ,空间 (两份 的
long long差分数组约 65 MB)。代码
#include<bits/stdc++.h> #define int long long using namespace std; const int M = 2020; // 坐标最大 2000,多留几个位置给差分边界 void go(){ vector<vector<int>> a(M,vector<int>(M,0)); // 每个格子被多少摊位覆盖 vector<vector<int>> b(M,vector<int>(M,0)); // 覆盖该格子的摊位编号之和 int n; cin >> n; for(int k=1;k<=n;k++){ int u,d,l,r; cin >> u >> d >> l >> r; // 覆盖次数的二维差分:四个角分别加减 1 a[u][l]++, a[d+1][r+1]++; a[u][r+1]--, a[d+1][l]--; // 摊位编号和的二维差分:四个角分别加减 k b[u][l]+=k, b[d+1][r+1]+=k; b[u][r+1]-=k, b[d+1][l]-=k; } // 二维前缀和还原出每个格子的真实值 for(int i=1;i<M;i++){ for(int j=1;j<M;j++){ a[i][j] += a[i-1][j]+a[i][j-1]-a[i-1][j-1]; b[i][j] += b[i-1][j]+b[i][j-1]-b[i-1][j-1]; } } vector<int> bk(n+1,0); // bk[0] 统计未覆盖格,bk[k] 统计只被 k 覆盖的格 for(int i=1;i<=2000;i++){ for(int j=1;j<=2000;j++){ if(a[i][j]==0){bk[0]++;} // 从未被覆盖 else if(a[i][j]==1){bk[b[i][j]]++;} // 只被一个摊位覆盖,b 即其编号 } } // 取消第 i 个摊位后变成空闲的格子数 for(int i=1;i<=n;i++){ cout << bk[0]+bk[i] << "\n"; } } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int _=1; // 本题只有一组数据,不需要读入测试组数 while(_--){ go(); } return 0; }
- 1
信息
- ID
- 27
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者