Wannafly 挑战赛13 E VVQ 与线段 【思维 + 线段树】

传送门
题意: 一维数轴上给定很多线段, 求任意两条相交线段的异或最小值, 定义线段的异或值为它们并的长度减他们交的长度.

思路: 我们随便画出一个样例可得, 对于两条相交直线[l1, r1], [l2, r2], 他们的异或值为(r2+l2) - (r1+l1), 且l2 <= r1 <= r2, 所以很明显可以得出ans = max((r2+l2) - (r1+l1)), 且l2 <= r1 <= r2, 所以我们先对线段排序, r小的在前面, 其次l大的在前面, 所以我们开始枚举每一条线段, 找到与该条线段满足相交要求的r存在的区间范围, 这样再这个区间范围内的r1 + l1的min值就是最优的答案, 维护一个区间最值, 当然用线段树呀, 随便维护下就行了, 然后我们寻找时用二分找, 因为要在结构体数组中二分, 所以要手写二分, 注意边界问题, 即找不到的情况. 然后求区间min值注意不要把当前枚举的这条线段加入计算. 这样算下来的ans是所有没有包含的情况的最优值, 所以我们还要算一遍包含情况下的最优值与ans取一个max值就是答案了. 注意算包含情况时要重新排一次序…… 具体细节请看代码…

AC Code

const int maxn = 2e5+5;
struct node {
    int l, r;
}p[maxn];
bool cmp1(node x, node y) {
    if (x.r != y.r) return x.r < y.r;
    return x.l > y.l;
}
bool cmp2(node x, node y) {
    if (x.l != y.l) return  x.l < y.l;
    return x.r > y.r;
}
int a[maxn];
struct Tree{
    int tl, tr;
    ll minn;
} tree[maxn*4];

void pushup(int id)
{
    tree[id].minn = min(tree[id<<1].minn,tree[id<<1|1].minn);
}


void build(int id,int l,int r)
{
    tree[id].tl = l; tree[id].tr = r;
    if(l == r){
        tree[id].minn = p[l].l + p[l].r;
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}

ll mi;
void query(int id, int ql, int qr)
{
    int l = tree[id].tl , r = tree[id].tr;
    if(ql <= l && r <= qr) {
        mi = min(mi, tree[id].minn);
        return ;
    }
    int mid = (l+r) >> 1 ;
    if(ql <= mid) query(id<<1, ql, qr);
    if(qr > mid) query(id<<1|1, ql, qr);
}
int n;
int bfind(int x) {
    int l = 1, r = n, mid, ans = -1;
    while(l <= r) {
        mid = (l + r) >> 1;
        if (p[mid].r >= x) {
            r = mid - 1;
            ans = mid;
        }
        else l = mid + 1;
    }
    if (ans == -1) ans = n + 1;
    return ans;
}
void solve()
{
    scanf("%d", &n);
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%d%d", &p[i].l, &p[i].r);
    }
    sort(p+1, p+1+n, cmp1);
    build(1, 1, n);
    ll ans = 0;
    for (int i = 1 ; i <= n ; i ++) {
        int p1 = bfind(p[i].l), p2 = bfind(p[i].r+1)-1;
        if (p1 >= p2) continue;
        ll t1, t2;
        mi = inf; query(1, p1, i-1); t1 = mi;
        mi = inf; query(1, i+1, p2); t2 = mi;
        ans = max(ans, p[i].r+p[i].l - min(t1, t2));
    }
    sort(p+1, p+1+n, cmp2);
    node tt = p[1];
    for (int i = 2 ; i <= n ; i ++) {
        if (p[i].r > tt.r) tt = p[i];
        else {
            ans = max(ans, 1ll*tt.r - tt.l - p[i].r + p[i].l);
        }
    }
    printf("%lld\n", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值