题目链接:https://nanti.jisuanke.com/t/31459
样例输入
3 1 4 4 1 3 3
样例输出
10
题意:
二维平面上给出 $n$ 个点,每个点坐标 $left( {x,y} ight)$ 代表一个从原点到 $left( {x,y} ight)$ 的长方形,
其中标记红线为线段 $left( {x,0} ight)left( {x,y} ight)$ 和 $left( {0,y} ight)left( {x,y} ight)$,
每次往二维平面上放置长方形会覆盖住之前放置的长方形,求 $n$ 个长方形全部放置完之后,整个图形上剩余的红线的总长度。
题解:
$x$ 方向和 $y$ 方向可以分开来看,分成 $n$ 个平行于 $x$ 轴的线段和 $n$ 个平行于 $y$ 轴的线段,
不妨看 $n$ 个平行于 $x$ 轴的线段(平行 $x$ 轴的和平行 $y$ 轴的计算方式是一样的),
对于第 $i$ 条线段,其后面的第 $i+1$ 到 第$n$ 条线段,若他们的 $y$ 坐标大于等于当前线段,那么就会覆盖掉一部分(乃至全部)的当前线段,
我们只要找出:第 $i+1$ 到 第$n$ 条线段中,满足 $y$ 坐标大于等于当前线段的,最长的那一条($x$ 值最大的那一条),
这条线段的 $x$ 值,决定了当前第 $i$ 条线段被覆盖掉了多少,那么剩下的就是对答案的贡献,
所以我们从 $n$ 开始递减枚举,用线段树维护区间最大值(当然,坐标需要离散化,否则太大了),不断累加每条线段的贡献即可。
时间复杂度 $Oleft( {nlog n} ight)$。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=5e4+10; int n; struct Point{ ll x,y; }p[maxn]; vector<ll> x; inline int getxid(int val){return lower_bound(x.begin(),x.end(),val)-x.begin();} vector<ll> y; inline int getyid(int val){return lower_bound(y.begin(),y.end(),val)-y.begin();} /********************************* Segment Tree - st *********************************/ struct Node{ int l,r; int val; }node[4*maxn]; void pushup(int root) { node[root].val=max(node[root*2].val,node[root*2+1].val); } void build(int root,int l,int r) { if(l>r) return; node[root].l=l; node[root].r=r; node[root].val=0; if(l==r) return; else { int mid=l+(r-l)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); pushup(root); } } void update(int root,int pos,int val) { if(node[root].l==node[root].r) { node[root].val=max(node[root].val,val); return; } int mid=node[root].l+(node[root].r-node[root].l)/2; if(pos<=mid) update(root*2,pos,val); if(pos>mid) update(root*2+1,pos,val); pushup(root); } int askmax(int root,int st,int ed) { if(st>node[root].r || ed<node[root].l) return -INF; if(st<=node[root].l && node[root].r<=ed) return node[root].val; else return max(askmax(root*2,st,ed),askmax(root*2+1,st,ed)); } /********************************* Segment Tree - ed *********************************/ int main() { scanf("%d",&n); x.clear(); x.push_back(0); y.clear(); y.push_back(0); for(int i=1;i<=n;i++) { scanf("%lld%lld",&p[i].x,&p[i].y); x.push_back(p[i].x); y.push_back(p[i].y); } sort(x.begin(),x.end()); x.erase(unique(x.begin(),x.end()),x.end()); sort(y.begin(),y.end()); y.erase(unique(y.begin(),y.end()),y.end()); build(1,0,y.size()); ll X=0; for(int i=n;i>=1;i--) { int yid=getyid(p[i].y); int xid=getxid(p[i].x); int mx=askmax(1,yid,y.size()); if(xid>mx) X+=(ll)(p[i].x-x[mx]); update(1,yid,xid); } build(1,0,x.size()); ll Y=0; for(int i=n;i>=1;i--) { int yid=getyid(p[i].y); int xid=getxid(p[i].x); int my=askmax(1,xid,x.size()); if(yid>my) Y+=(ll)(p[i].y-y[my]); update(1,xid,yid); } cout<<X+Y<<endl; }