首先计算宽度,维护一棵线段树存之前扫描过的线段中时间比当前边大的长度
于是可以线段树下标为时间,值为长度,因为线段树要做到子节点的信息能往上传。如果下标为长度,值为时间,我们就不能动态地计算时间大于 t 时的长度!
ac代码:
#include<bits/stdc++.h> #define per(i,a,b) for(int i=a;i<=b;i++) #define mod 1000000007 using namespace std; typedef long long ll; //#define int long long const int inf =0x3f3f3f3f; const double eps=1e-8; int read(){ char ch=getchar(); int res=0,f=0; while(ch<'0' || ch>'9'){f=(ch=='-'?-1:1);ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+(ch-'0');ch=getchar();} return res*f; } // ------------------------head const int siz=5e4+5; int n; int tr[siz*4];//维护一棵时间线段树来存某时间前的长度 struct Node{ int w,h,t;//w宽度 h高度 }node[siz]; bool cmp1(Node a,Node b){return a.h>b.h;} bool cmp2(Node a,Node b){return a.w>b.w;} int query(int u,int l,int r,int para){ if(l>=para)return tr[u]; int mid=l+r>>1; if(mid>=para)return max(query(u<<1,l,mid,para),query(u<<1|1,mid+1,r,para)); else if(mid<para)return query(u<<1|1,mid+1,r,para); } void update(int u,int l,int r,int t,int v){ if(l==r){tr[u]=max(tr[u],v);;return;} int mid=(l+r>>1); if(t<=mid)update(u<<1,l,mid,t,v); else if(t>mid)update(u<<1|1,mid+1,r,t,v); tr[u]=max(tr[u<<1],tr[u<<1|1]); } signed main() { scanf("%d",&n); memset(tr,0,sizeof(tr)); per(i,1,n){ scanf("%d %d",&node[i].w,&node[i].h); node[i].t=i; } ll ans=0; sort(node+1,node+n+1,cmp1); for(int i=1;i<=n;i++){//按照高度排序,计算宽度 int num=query(1,1,n,node[i].t); if(node[i].w>num){ ans+=(ll)(node[i].w-num); } update(1,1,n,node[i].t,node[i].w); } memset(tr,0,sizeof(tr)); sort(node+1,node+1+n,cmp2); for(int i=1;i<=n;i++){//按照宽度排序,计算高度 int num=query(1,1,n,node[i].t);//num即按宽降序(前面的宽度都是更大的)后,前面出现的线段中高度最高的 if(node[i].h>num)ans+=(ll)(node[i].h-num); update(1,1,n,node[i].t,node[i].h); } printf("%lld ",ans); return 0; }