Wannafly挑战赛13 E VVQ 与线段【二分预处理+线段树区间查询】

链接:https://www.nowcoder.com/acm/contest/80/E
来源:牛客网
题目描述
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

分析:(有点运气成分了)二分预处理+线段树;
先贪心左端排个序(右端同理),遍历每一条线段。对于排序后的每一条线段,左端是升序排列,从右端可以画一条竖线,有交点的线段才会存在异或值。怎么把有交点的线段给找出来呢?由于是有序的,可以根据枚举线段的右端点通过二分所有线段的左端点,且找到的是一个区间【i,res】,在这个满足条件的区间里分两种情况:1,枚举的线段[x1,y1]包含了一部分区间线段[x2, y2],即:x1<=x2<=y2<=y1,对于这种情况:异或值=y1 - x1 - (y2 - x2),只需要维护区间【R-L】的最小值即可;2,枚举的线段[x1,y1]交叉了一部分区间线段[x2, y2],即:x1<=x2<=y1<=y2,对于这种情况:异或值=y2 + x2 - (y1 + x1),只需要维护区间【R+L】的最大值即可。
对于区间可以用线段树维护,这道题主要是二分的预处理,这个解题的关键;

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2e5 + 10;
int dp1[MAXN << 2], dp2[MAXN << 2], arr[MAXN];

struct node {
    int l;
    int r;
}s[MAXN];

bool cmp(node x, node y) {
    if(x.l != y.l) return x.l < y.l;
    return x.r < y.r;
}

inline void pushup1(int root) {
    dp1[root] = min(dp1[root << 1], dp1[root << 1 | 1]);
}

inline void pushup2(int root) {
    dp2[root] = max(dp2[root << 1], dp2[root << 1 | 1]);
}

inline void build1(int root, int L, int R) {
    if(L == R) {
        dp1[root] = s[L].r - s[L].l;
        return ;
    }
    int mid = (L + R) >> 1;
    build1(root << 1, L, mid);
    build1(root << 1 | 1, mid + 1, R);
    pushup1(root);
}

inline void build2(int root, int L, int R) {
    if(L == R) {
        dp2[root] = s[L].r + s[L].l;
        return ;
    }
    int mid = (L + R) >> 1;
    build2(root << 1, L, mid);
    build2(root << 1 | 1, mid + 1, R);
    pushup2(root);
}

inline int query1(int root, int L, int R, int l, int r) {
    if(l <= L && R <= r) {
        return dp1[root];
    }
    int ans = 1e9;
    int mid = (L + R) >> 1;
    if(l <= mid) ans = min(ans, query1(root << 1, L, mid, l, r));
    if(r > mid) ans = min(ans, query1(root << 1 | 1, mid + 1, R, l, r));
    return ans;
}

inline int query2(int root, int L, int R, int l, int r) {
    if(l <= L && R <= r) {
        return dp2[root];
    }
    int ans = 0;
    int mid = (L + R) >> 1;
    if(l <= mid) ans = max(ans, query2(root << 1, L, mid, l, r));
    if(r > mid) ans = max(ans, query2(root << 1 | 1, mid + 1, R, l, r));
    return ans;
}

int main() {
    int n, l, r;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d %d", &s[i].l, &s[i].r);
    sort(s + 1, s + n + 1, cmp);
    for(int i = 1; i <= n; ++i) {
        arr[i] = s[i].l;
    }
    build1(1, 1, n);
    build2(1, 1, n);
    int ans = 0;
    for(int i = 1; i <= n; ++i) {
        int cnt = s[i].r;
        int res = upper_bound(arr + 1, arr + n + 1, cnt) - arr;
        ans = max(ans, cnt - s[i].l - query1(1, 1, n, i, res - 1));
        ans = max(ans, query2(1, 1, n, i, res - 1) - cnt - s[i].l);
    }
    printf("%d\n", ans);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_36368339/article/details/79858258