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;
}