【BZOJ】1645: [Usaco2007 Open]City Horizon 城市地平线(线段树+特殊的技巧)
http://www.lydsy.com/JudgeOnline/problem.php?id=1645
这题的方法很奇妙啊。。。一开始我打了一个“离散”后的线段树。。。。。。。。。。。。。果然爆了。。(因为压根没离散)
这题我们可以画图知道,每2个点都有一个区间,而这个区间的高度是一样的,因此,我们只需要找相邻的两个点,用他们的距离×这个区间的高度就是这块矩形的面积。
将所有这样的矩形累计起来就是答案了。
因此线段树就离散到了O(n)的大小。。真神。。
只需要维护点的位置,然后维护区间最值即可(因为这是线段长度而不是两点长度,即r-l+1,所以要用一定的技巧,将这些坐标都往左边缩1,原因很简单,画图得知)
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%lld", a) #define dbg(x) cout << (#x) << " = " << (x) << endl #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; } inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const int min(const int &a, const int &b) { return a<b?a:b; } typedef long long ll; #define lc x<<1 #define rc x<<1|1 #define lson l, m, lc #define rson m+1, r, rc #define MID (l+r)>>1 const int N=40005; int n, b[N+N]; ll ans; struct dat { int x, y, h; }a[N]; struct nod { int h, flg; }t[N<<4]; void pushup(int x) { t[x].h=max(t[lc].h, t[rc].h); } void pushdown(int x) { if(t[x].flg) { int flg=t[x].flg; t[x].flg=0; t[lc].flg=max(t[lc].flg, flg); t[lc].h=max(t[lc].h, flg); t[rc].flg=max(t[rc].flg, flg); t[rc].h=max(t[rc].h, flg); } } void update(int l, int r, int x, int L, int R, int fix) { pushdown(x); if(L<=l && r<=R) { t[x].flg=fix; t[x].h=max(t[x].h, fix); return; } int m=MID; if(L<=m) update(lson, L, R, fix); if(m<R) update(rson, L, R, fix); pushup(x); } int query(int l, int r, int x, int L) { pushdown(x); if(l==r) return t[x].h; int m=MID; if(L<=m) return query(lson, L); else return query(rson, L); } int main() { read(n); for1(i, 1, n) read(a[i].x), read(a[i].y), read(a[i].h), b[i<<1]=a[i].x, b[(i<<1)-1]=a[i].y; int sz=n<<1; sort(b+1, b+1+sz); for1(i, 1, n) a[i].x=lower_bound(b+1, b+1+sz, a[i].x)-b, a[i].y=lower_bound(b+1, b+1+sz, a[i].y)-b; for1(i, 1, n) update(1, sz, 1, a[i].x, a[i].y-1, a[i].h); for1(i, 1, sz-1) ans+=(ll)query(1, sz, 1, i)*(ll)(b[i+1]-b[i]); print(ans); return 0; }
Description
Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouettes formed by the rectangular buildings. The entire horizon is represented by a number line with N (1 <= N <= 40,000) buildings. Building i's silhouette has a base that spans locations A_i through B_i along the horizon (1 <= A_i < B_i <= 1,000,000,000) and has height H_i (1 <= H_i <= 1,000,000,000). Determine the area, in square units, of the aggregate silhouette formed by all N buildings.
N个矩形块,交求面积并.
Input
* Line 1: A single integer: N
* Lines 2..N+1: Input line i+1 describes building i with three space-separated integers: A_i, B_i, and H_i
Output
* Line 1: The total area, in square units, of the silhouettes formed by all N buildings
Sample Input
2 5 1
9 10 4
6 8 2
4 6 3
Sample Output
OUTPUT DETAILS:
The first building overlaps with the fourth building for an area of 1
square unit, so the total area is just 3*1 + 1*4 + 2*2 + 2*3 - 1 = 16.