2018 徐州网络赛 G 题解

电波~

这题首先要倒着贴这样 每次➕就好了 还有就是 数据太大需要离散化

然后建线段树,根据x轴的坐标建坐标轴 ,看  这个点的 max(y) 有多大 如果 y[i]> max(y) 产生 贡献 ans+=y[x]-max(x)

x轴同理 

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000001
struct ac{
  int x,y;
}b[maxn];
int a[maxn],lz[maxn],c[maxn];
int n,tot=1,t=1;
void updata(int x,int y,int l,int r,int va,int in){
   if(x==l&&y==r){
       c[in]=max(c[in],va);
       lz[in]=max(lz[in],va);
       return ;
   }
   int mid=(l+r)/2;
   if(lz[in]){
       c[in*2]=max(lz[in],c[in*2]);
       c[in*2+1]=max(lz[in],c[in*2+1]);
       lz[in*2]=max(lz[in],lz[in*2]);
       lz[in*2+1]=max(lz[in],lz[in*2+1]);
       lz[in]=0;
   }
   if(x>mid){
      updata(x,y,mid+1,r,va,in*2+1);
   }else if(y<=mid){
      updata(x,y,l,mid,va,in*2);
   }else{
      updata(mid+1,y,mid+1,r,va,in*2+1);
      updata(x,mid,l,mid,va,in*2);
   }
   c[in]=max(c[in*2],c[in*2+1]);
}
int query(int x,int l,int r,int in){
   if(l==r){
      return c[in];
   }
   int mid=(l+r)/2;
   if(lz[in]){
       c[in*2]=max(lz[in],c[in*2]);
       c[in*2+1]=max(lz[in],c[in*2+1]);
       lz[in*2]=max(lz[in],lz[in*2]);
       lz[in*2+1]=max(lz[in],lz[in*2+1]);
       lz[in]=0;
   }
   if(x>mid){
      return query(x,mid+1,r,in*2+1);
   }
   return query(x,l,mid,in*2);
}
int main(){
   cin>>n;
   for(int j=1;j<=n;j++){
      cin>>b[j].x>>b[j].y;
      a[tot++]=b[j].x;
      a[tot++]=b[j].y;
   }
   sort(a+1,a+tot);
   for(int i=2;i<tot;i++)if(a[i]!=a[i-1])a[++t]=a[i];
   long long ans=0;
   memset(c,0,sizeof(c));
   memset(lz,0,sizeof(lz));
   int l=lower_bound(a+1,a+t+1,b[n].x)-a;
   int r=lower_bound(a+1,a+t+1,b[n].y)-a;
   ans+=a[r]+a[l];
   //cout<<ans<<endl;
   updata(1,l,1,t,r,1);           // 把 1-x 全部更新成 y 的最大值(离散化之后是坐标)
   for(int j=n-1;j>=1;j--){
      int l=lower_bound(a+1,a+t+1,b[j].x)-a;
      int r=lower_bound(a+1,a+t+1,b[j].y)-a;
      int i=query(l,1,t,1);
      if(i<r){
         ans+=a[r]-a[i];
      }
      int ll=1,rr=l;
      int mi=1e9;
      while(ll<=rr){                 //我们要找比y小的最小的x 这样才会有贡献
         int mid=(ll+rr)/2;
         i=query(mid,1,t,1);
         if(i<r){
            mi=min(mi,mid);         // 说明这个点的mid这个点的y < 当前j 点的y 可以产生贡献取min(x)  
            rr=mid-1;
         }else ll=mid+1;
      }
      if(mi!=1e9){
         ans+=a[l]-a[ll-1];
      }
      updata(1,l,1,t,r,1);
   }
   cout<<ans<<endl;
}

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值