Wannafly挑战赛13 E VVQ 与线段
思路:
- 对于两条不相交的线段i, j(假设j在右边),他们的异或值为\(r_j-r_i + l_j - l_i = r_j+l_j - r_i - l_i\),所以直接对线段的\(l+r\)排序,找到有公共端点且\(l+r\)的差值最大的两条线段
- 对于不相交的线段i,j(假设j包含i),他们的异或值为\(r_j-l_j-(r_i-l_i)\),所以对于相互包含的线段,我们只需找到\(r_j-l_j-(r_i-l_i)\)的最大值
- 答案显然就是以上两种情况的最大值
实现:
- 先将所有线段先按x轴排序, 再按y轴排序;对于情况(1),然后定义一个按\(l + r\)升序的优先队列(队首元素最小),对于每个要加入队列的点,找到第一个相交且\(l+r\)最小的线段,相减即可
- 对于情况(2),定义一个按\(r-l\)降序的优先队列(队首元素最大),对于每个点,判断队列里最长的线段是否包含当前线段,若包含,判断是否更新最大值即可最大值即可
Hint:
- 这道题目数据有点弱,好多已经过了的代码过不了下面的两组数据
4
1 100
80 83
81 82
60 120
4
1 100
80 83
81 82
40 180
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
int n, m;
struct P {
int l, r;
bool operator < (const P &t) const {
return l + r > t.l + t.r;
}
} p[maxn];
bool cmp(P a, P b) {
return a.l == b.l ? a.r < b.r : a.l < b.l;
}
int main() {
while(~scanf("%d", &n)) {
for(int i = 0; i < n; i++) scanf("%d %d", &p[i].l, &p[i].r);
sort(p, p + n, cmp);
priority_queue<P> q;
priority_queue<P> Q;
q.push(p[0]);
Q.push({p[0].l, -p[0].r});
int ans = 0;
for(int i = 1; i < n; i++) {
while(!Q.empty() && -Q.top().r < p[i].l) Q.pop();
if(!Q.empty() && -Q.top().r > p[i].r) ans = max(ans, -(Q.top().r + Q.top().l) - p[i].r + p[i].l);
Q.push({p[i].l, -p[i].r});
while(!q.empty() && q.top().r < p[i].l) q.pop();
//p中所有点已按l排序,当前点与队列里第一个点不相交,后面的点一定不相交
if(!q.empty()) ans = max(ans, p[i].l + p[i].r - q.top().l- q.top().r);
q.push(p[i]);
}
printf("%d\n", ans);
}
return 0;
}