1 条题解
-
0Guest LV 0 MOD
-
1
#include<cstdio> #include<algorithm> using namespace std; int n; long long ans; int t; struct node { int left,right; int c; } tree[4*40005*2]; struct edge { int left,right,h; } a[40005]; int p[2*40005]; bool cmp(edge e1,edge e2) { return e1.h<e2.h; } //二分查找当前所要修改的离散化区间,即对应的矩形顶点的区间, //比如样例里,当处理第一个矩形时,修改的区间为(1,2), //即第一个矩形的两个顶点在p数组中对应的下标为1、2; int erfen(int l,int r,int x) { while(l<=r) { int mid=(l+r)/2; if(p[mid]==x) return mid; else if(p[mid]>x) r=mid-1; else l=mid+1; } return 0; } void change(int now,int l,int r,int x) //裸的区间修改 { if(tree[now].right<l||tree[now].left>r) return; if(tree[now].left>=l&&tree[now].right<=r) { tree[now].c=x; return; } int mid=(tree[now].left+tree[now].right)/2; if(tree[now].c) { tree[now*2].c=tree[now].c; tree[now*2+1].c=tree[now].c; tree[now].c=0; } if(mid>=r) change(now*2,l,r,x); else if(mid<=l) change(now*2+1,l,r,x); else { change(now*2,l,r,x); change(now*2+1,l,r,x); } } void built(int now,int l,int r) { tree[now].left=l; tree[now].right=r; tree[now].c=0; if(l==r-1) return; built(now*2,l,(l+r)/2); built(now*2+1,(l+r)/2,r);//*右界要包括mid,因为一个矩形所占的位置肯定大于一个点,如果不包括mid,会漏掉一些矩形; } void quest(int now) { if(tree[now].c) { ans+=(p[tree[now].right]-p[tree[now].left])*(long long)tree[now].c;//矩形面积 return; } if(tree[now].right==tree[now].left+1) return; quest(now*2); quest(now*2+1); } int main() { scanf("%d",&n);//n个区间 for(int i=1; i<=n; i++) { scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].h); p[++t]=a[i].left; p[++t]=a[i].right; }//离散化顶点 sort(p+1,p+1+2*n);//每个区间2个点,所以是2n个点,将所有点从小到大排序 sort(a+1,a+n+1,cmp);//按每个区间的高度从小到大排序 built(1,1,n*2);//建树,每个叶子结点其实是p数组的一个下标 for(int i=1; i<=n; i++) { int l=erfen(1,2*n,a[i].left);//l和下面的r都是p数组的下标 int r=erfen(1,2*n,a[i].right); change(1,l,r,a[i].h); } quest(1); printf("%lld",ans); }
这一题关键有\(4\)点:
\(1\)、离散化
为什么需要离散化?因为区间范围太大了,区间范围长度就是线段树叶子结点个数。
没有办法建立一个这么大线段树。
但是区间的个数是有限的,所以用区间的总端点数(区间数\(×2\))来建立一棵线段树
最后需要来查找区间的时候,就去该离散化后的线段树上去查找。
因为是先对\(p\)数组排序后再建立线段树的,所以\(a[i]\)位置小的自然\(p[i]\)的位置也小\(2\)、对区间按高度从小到大排序
因为只有排过序,后面的高度比前面的更高,这样修改才不至于覆盖掉前面的内容。\(3\)、本题的\(tree[now].c\)相当于是\(lazy\)标记,因为就只查\(1\)次,所以查询时不需要做标记下传动作。
\(4\)、 \(tree[now].c\)相当于\(lazy\)标记,其实他表示的是\(tree[now].left\)到
\(tree[now].right\)这个区间的高
那为什么有时候会是\(0?\)
因为有时候这个区间并没有一个统一的高度,而是多个不同高度的矩形组合而成的
所以就要继续向下搜索孩子区间,直到发现\(tree[now].c\)不为\(0\),
此时这个区间高度确定了,此时直接拿区间长度\(×\)区间高度
- 1