链接:https://www.nowcoder.com/acm/contest/80/E
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
VVQ 最近迷上了线段这种东西
现在他手上有 n 条线段,他希望在其中找到两条有公共点的线段,使得他们的异或值最大。 定义线段的异或值为它们并的长度减他们交的长度
输入描述:
第一行包括一个正整数 n,表示 VVQ 拥有的线段条数。 接下来 n 行每行包括两个正整数 l,r,表示 VVQ 拥有的线段的 左右端点。
输出描述:
一行一个整数,表示能得到的最大异或值
思路:分类讨论 完全包含或者不完全包含 线段树
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int maxn=200010; const int INF=0x3fffffff; //线段按照左端点大小顺序排序 struct node { int l,r; friend bool operator <(const node &a,const node &b) { return a.l<b.l; } }a[maxn]; int Max[maxn<<2],Min[maxn<<2]; //建线段树 void build(int l,int r,int root) { if(l==r) { Max[root]=a[l].l+a[l].r; Min[root]=a[l].r-a[l].l; return; } int mid=(l+r)>>1; build(l,mid,root*2); build(mid+1,r,root*2+1); Max[root]=max(Max[root*2],Max[root*2+1]); Min[root]=min(Min[root*2],Min[root*2+1]); } //第一种查询 int Quary_Max(int l,int r,int root,int sl,int sr) { if(l>sr||r<sl)return 0; if(l>=sl&&r<=sr)return Max[root]; int mid=(l+r)>>1; return max(Quary_Max(l,mid,root*2,sl,sr),Quary_Max(mid+1,r,root*2+1,sl,sr)); } //第二种查询 int Quary_Min(int l,int r,int root,int sl,int sr) { if(l>sr||r<sl)return INF; if(l>=sl&&r<=sr)return Min[root]; int mid=(l+r)>>1; return min(Quary_Min(l,mid,root*2,sl,sr),Quary_Min(mid+1,r,root*2+1,sl,sr)); } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].l,&a[i].r); sort(a+1,a+1+n); build(1,n,1); int ans=0; node tmp; tmp.r=0; int l,r; for(int i=1;i<=n;i++) { tmp.l=a[i].l; l=lower_bound(a+1,a+1+n,tmp)-a; //找到a[j].l>=a[i].l的第一个j tmp.l=a[i].r; r=upper_bound(a+1,a+1+n,tmp)-a-1; //找到a[j].l<=a[i].r的最后一个j if(l>r)continue; //这样就找到左端点在线段i范围内的所有线段 ans=max(ans,Quary_Max(1,n,1,l,r)-a[i].r-a[i].l); ans=max(ans,a[i].r-a[i].l-Quary_Min(1,n,1,l,r)); } printf("%d\n",ans); }