1 条题解
-
0
自动搬运
来自洛谷,原作者为

Jerrywang09
Пусть сильнее грянет буря!搬运于
2025-08-24 22:56:27,当前版本为作者最后更新于2024-04-21 17:49:58,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
阅读题解前请确保完全理解题面。
首先有一个性质,想不到就没法做题了:假设有柱子 有着相同的横坐标,一定是形如 的一对柱子中间连了栅栏,形如 的一对柱子中间一定没连。对于有相同纵坐标的同理。
剩下的比较套路。连边后构成一个环图,dfs 找出环的顺序,破环成链,用差分维护区间修改即可。代码很难写。
在实现中,我将询问中的点与柱子一起处理。然后对于同一行(列)的点,找到相邻的两个柱子,并把其间的询问点一起连上。迭代器的处理也很繁琐。
如何处理重复的点也是个问题。各数组的含义详见代码注释。
// Title: Painting Fence Posts // Source: USACO24OPEN Silver // Author: Jerrywang #include <bits/stdc++.h> #define F first #define S second #define pii pair<int, int> #define ll long long #define rep(i, s, t) for(int i=s; i<=t; ++i) #define debug(x) cerr<<#x<<":"<<x<<endl; const int N=1000010; using namespace std; int n, nn, m; map<int, set<int>> row, col; // row,col: 相同行(列)上的点的列(行)坐标 map<pii, int> id; pii point[N]; // point[i]: 原始编号为i的点的坐标 // id[{x,y}]: 坐标为(x,y)的点的最小原始编号 vector<int> g[N]; int a[N], a_id[N], cnt[N]; ll d[N]; // a[i]: 环上编号为i的点的原始编号 // a_id[i]: 原始编号为i的点的环上编号 ll dis(pii a, pii b) { return abs(a.F-b.F)+abs(a.S-b.S); } void add(int u, int v) { g[u].push_back(v), g[v].push_back(u); } bool vis[N]; void dfs(int u) { a[++nn]=u; vis[u]=1; for(int v:g[u]) if(!vis[v]) dfs(v); } int main() { #ifdef Jerrywang freopen("E:/OI/in.txt", "r", stdin); #endif scanf("%d%d", &m, &n); rep(i, 1, n) { int x, y; scanf("%d%d", &x, &y); id[{x, y}]=i, point[i]={x, y}; row[x].insert(y), col[y].insert(x); } rep(i, 1, m) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); point[n+i]={x1, y1}, point[n+m+i]={x2, y2}; if(!id[{x1, y1}]) id[{x1, y1}]=n+i, row[x1].insert(y1), col[y1].insert(x1); if(!id[{x2, y2}]) id[{x2, y2}]=n+m+i, row[x2].insert(y2), col[y2].insert(x2); } for(auto &[x,S]:row) { auto i=S.begin(); while(i!=S.end()) { for(; i!=S.end(); i++) if(id[{x, *i}]<=n) break; auto j=next(i), k=i; for(; j!=S.end(); j++) if(id[{x, *j}]<=n) break; if(j==S.end()) break; for(; k!=j; k++) add(id[{x, *k}], id[{x, *next(k)}]); i=next(j); } } for(auto &[y,S]:col) { auto i=S.begin(); while(i!=S.end()) { for(; i!=S.end(); i++) if(id[{*i, y}]<=n) break; auto j=next(i), k=i; for(; j!=S.end(); j++) if(id[{*j, y}]<=n) break; if(j==S.end()) break; for(; k!=j; k++) add(id[{*k, y}], id[{*next(k), y}]); i=next(j); } } dfs(1); rep(i, 1, nn) a[nn+i]=a[i], a_id[a[i]]=i; rep(i, 2, nn+nn) d[i]=dis(point[a[i]], point[a[i-1]]), d[i]+=d[i-1]; rep(i, 1, m) { int u=a_id[id[point[n+i]]], v=a_id[id[point[n+m+i]]]; ll d1, d2; if(d[u]<d[v]) { d1=d[v]-d[u], d2=d[nn+u]-d[v]; if(d1<d2) cnt[u]++, cnt[v+1]--; else cnt[v]++, cnt[nn+u+1]--; } else { d1=d[u]-d[v], d2=d[nn+v]-d[u]; if(d1<d2) cnt[v]++, cnt[u+1]--; else cnt[u]++, cnt[nn+v+1]--; } } rep(i, 1, nn+nn) cnt[i]+=cnt[i-1]; rep(i, 1, n) printf("%d\n", cnt[a_id[i]]+cnt[nn+a_id[i]]); return 0; }
- 1
信息
- ID
- 9921
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者