VVQ 与线段-线段树+扫描线/二分

Description

  utsuho 有 n 条线段,现在她希望在其中找到两条有公共点的线段,使得它们的 异或值 最大。
  定义线段异或值为它们并的长度减它们交的长度.

Input

  从文件 ut.in 中读入数据。
  输入的第一行包括一个正整数 n,表示 Utsuho 的线段的个数。
  接下来 n 行每行包括两个正整数 l,r,表示 Utsuho 拥有的线段的左右端点。

Output

  输出到文件 ut.out 中。
  输出一行一个整数,表示能得到的最大异或值。

Sample Input

3
10 100
1 50
50 100

Sample Output

99


思路

  • 看数据范围1<=n<=200000,1<=l<=r<=1e8,n<=200000推断此题算法应该为O(N)或O(logn)

  • 分析问题,要求任意有公共点的两条线段的异或值,首先想到两条线段一维的关系:包含,相交;

  • 设线段A左右端点为LA,RA,线段B左右端点为LB,RB

  • 包含(设B包含在A中):线段异或值=LB-LA+RA-RB

  • 相交(设AL<BL):线段异或值=LB-LA-RA+RB

  • 同时处理L和R,二维偏序问题,想到先按左端点排序[套路],

  • 有相同的LB-LA,求极值转换为求另一部分的极值,又要满足有公共点(即区间极值),想到数据结构线段树

  • 可以扫描每一条线段,扫描到就加入线段树,借鉴某些题解的思路,也可以先将所有边加入后二分求极值


代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 200005
#define inf 0x7fffffff
using namespace std;
int n,temp[maxn],ans;
struct node1{int l,r,val;}e[maxn<<2],d[maxn<<2];
struct fdfdfd{int x,y;}a[maxn];
bool cmp(fdfdfd a,fdfdfd b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
int max(int a,int b){return a>b?a:b;}
void pushup1(int x){e[x].val=min(e[x<<1].val,e[x<<1|1].val);}
void pushup2(int x){d[x].val=max(d[x<<1].val,d[x<<1|1].val);}
void build1(int x,int left,int right)
{
	e[x].l=left; e[x].r=right;
	if(left==right){e[x].val=a[left].y-a[left].x; return;}
	int mid=(left+right)>>1;
	build1(x<<1,left,mid); build1(x<<1|1,mid+1,right);
	pushup1(x);
}
void build2(int x,int left,int right)
{
	d[x].l=left; d[x].r=right;
	if(left==right){d[x].val=a[left].y+a[left].x; return;}
	int mid=(left+right)>>1;
	build2(x<<1,left,mid); build2(x<<1|1,mid+1,right);
	pushup2(x);
}
int query1(int x,int left,int right)
{
	if(e[x].r<left||e[x].l>right) return inf;
	if(left<=e[x].l&&right>=e[x].r) return e[x].val;
	return min(query1(x<<1,left,right),query1(x<<1|1,left,right));
}
int query2(int x,int left,int right)
{
	if(d[x].r<left||d[x].l>right) return -inf;
	if(left<=d[x].l&&right>=d[x].r) return d[x].val;
	return max(query2(x<<1,left,right),query2(x<<1|1,left,right));
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;++i) temp[i]=a[i].x;
	build1(1,1,n); build2(1,1,n);
	for(int i=1;i<=n;++i)
	{
		int res=upper_bound(temp+1,temp+n+1,a[i].y)-temp-1;
		ans=max(ans,a[i].y-a[i].x-query1(1,i,res));
		ans=max(ans,query2(1,i,res)-a[i].x-a[i].y);
	}
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/13608719.html