线段相交的异或值 (线段树 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\n", 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\n", 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\n", ans); } return 0; }
东北日出西边雨 道是无情却有情