Wannafly挑战赛13 E VVQ 与线段

思路:

  1. 对于两条不相交的线段i, j(假设j在右边),他们的异或值为\(r_j-r_i + l_j - l_i = r_j+l_j - r_i - l_i\),所以直接对线段的\(l+r\)排序,找到有公共端点且\(l+r\)的差值最大的两条线段
  2. 对于不相交的线段i,j(假设j包含i),他们的异或值为\(r_j-l_j-(r_i-l_i)\),所以对于相互包含的线段,我们只需找到\(r_j-l_j-(r_i-l_i)\)的最大值
  3. 答案显然就是以上两种情况的最大值

实现:

  1. 先将所有线段先按x轴排序, 再按y轴排序;对于情况(1),然后定义一个按\(l + r\)升序的优先队列(队首元素最小),对于每个要加入队列的点,找到第一个相交且\(l+r\)最小的线段,相减即可
  2. 对于情况(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;
}

posted @ 2018-04-08 16:47  .ini  阅读(104)  评论(0编辑  收藏  举报