线段相交的异或值 (线段树 or 优先队列)

VVQ 最近迷上了线段这种东西

现在他手上有 n 条线段,他希望在其中找到两条有公共点的线段,使得他们的异或值最大。 定义线段的异或值为它们并的长度减他们交的长度

输入描述:

第一行包括一个正整数 n,表示 VVQ 拥有的线段条数。
接下来 n 行每行包括两个正整数 l,r,表示 VVQ 拥有的线段的 左右端点。

输出描述:

一行一个整数,表示能得到的最大异或值
示例1

输入

3 
10 100 
1 50 
50 100

输出

99

说明

选择第二条和第三条,99-0=99

备注:

1<=n<=200000,1<=l<=r<=1e8

题意 : 在坐标轴上面有很多线段,问你所有有公共点的线段的异或值最大是多少?
思路 : 所以线段只有 3 种情况, 1 是不相交, 2是相交, 3是包含,第一种情况的答案是 0, 对于第二种情况 假设2条线段i,j,且靠右的线段是 j,则此情况下的异或值是
rj+lj-(ri+li),将 i 看成是不变的量,让 j线段的值最大即可,线段树维护就可以了, 对于第三种情况,答案是 (rj-lj)-(ri-li),则此时值需要让 ri-rl的值最小即可。
代码示例 :
#define ll long long
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
#define lson k<<1
#define rson k<<1|1

struct edge
{
    int l, r;
    bool operator< (const edge &v)const{
        return l < v.l;
    }
}pre[maxn];

struct node
{
    int l, r;
    int mi,ma;
}t[maxn<<2];

void pushup(int k){
    t[k].ma = max(t[lson].ma, t[rson].ma);
    t[k].mi = min(t[lson].mi, t[rson].mi);
}

void build(int l, int r, int k){
    t[k].l = l;
    t[k].r = r;
    if (l == r){
        t[k].ma = pre[l].l+pre[l].r;
        t[k].mi = pre[l].r-pre[l].l;
        return;
    }
    int mid = (l+r) >> 1;
    build(l, mid, lson);
    build(mid+1, r, rson);
    pushup(k);
}
int sum = 0;
void query(int l, int r, int k){
    if (l <= t[k].l && t[k].r <= r){
        sum = max(sum, t[k].ma);
        return;
    }
    int m = (t[k].l+t[k].r)>>1;
    if (l <= m) query(l, r, lson);
    if (r > m) query(l, r, rson);
}

void query2(int l, int r, int k){
    if (l <= t[k].l && t[k].r <= r){
        sum = min(sum, t[k].mi);
        return;
    }
    int m = (t[k].l+t[k].r)>>1;
    if (l <= m) query2(l, r, lson);
    if (r > m) query2(l, r, rson);
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n;
    
    cin >>n;
    for(int i = 1; i <= n; i++){
        scanf("%d%d", &pre[i].l, &pre[i].r);
    }
    sort(pre+1, pre+1+n);
    build(1, n, 1);
    int ans = 0;
    edge tem;
    for(int i = 1; i <= n; i++){
        tem.l = pre[i].l;
        int p1 = lower_bound(pre+1, pre+1+n, tem)-pre;
        tem.l = pre[i].r;
        int p2 = upper_bound(pre+1, pre+1+n, tem)-pre-1; 
        sum = 0;
        //printf("p1 = %d p2 = %d
", p1, p2);
        query(p1, p2, 1);
        ans = max(ans, sum-(pre[i].l+pre[i].r));
        sum = inf;
        query2(p1, p2, 1);
        ans = max(ans, pre[i].r-pre[i].l-sum);
    }
    printf("%d
", ans);
    return 0;
}

方法二 : 优先队列(自己的超时了,先借鉴一个,待更新)

#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
", ans);
    }
    return 0;
}
东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/8781556.html