• 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;
    }
    
  • 相关阅读:
    事件对象
    事件方法on()
    each()遍历
    链接式操作
    理解选取更新范围
    net3.5 无网络环境安装
    visual studio 2017 报错 无法下载安装文件。请检查Internet连接,然后重试
    删除数据恢复数据语句 Oracle
    sqlserver还原数据库(mdf与ldf文件如何还原到SQLserver数据库)
    sqlserver2012卸载
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/13608719.html
Copyright © 2020-2023  润新知