1. 程式人生 > >luogu1856 [USACO5.5]矩形周長Picture

luogu1856 [USACO5.5]矩形周長Picture

另一個 UC cstring 線段樹 using sort != 貢獻 tro

看到一坨矩形就要想到掃描線。(poj atantis)

我們把橫邊豎邊分開計算,因為橫邊豎邊其實沒有區別,以下論述全為考慮豎邊的。

怎樣統計一個豎邊對答案的貢獻呢?答:把這個豎邊加入線段樹,當前的總覆蓋長度 減去 加入前的總覆蓋長度 的絕對值 即為這個豎邊的貢獻。

這樣做有一個要求,橫坐標相同的豎邊,要先加進去入邊再刪掉出邊。(為什麽呢?考慮兩個矩形,一個矩形的右邊和另一個矩形的左邊的橫坐標相同但上下錯落)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std; int n, qwq1, pwp1, qwq2, pwp2, cnt, m, num[20005], ans; struct Line{ int uu, vv, ww, id; }li1[10005], li2[10005]; bool cmp(Line x, Line y){ if(x.uu!=y.uu) return x.uu<y.uu; else return x.id>y.id; } struct SGT{ int sum[80005], len[80005]; void update(int o, int l, int
r, int x, int y, int k){ if(num[l]>=x && num[r]<=y) sum[o] += k; else{ int mid=(l+r)>>1; int lson=o<<1; int rson=lson|1; if(x<num[mid]) update(lson, l, mid, x, y, k); if(num[mid]<y) update(rson, mid, r, x, y, k); } if
(sum[o]>0) len[o] = num[r] - num[l]; else if(l+1==r) len[o] = 0; else len[o] = len[o<<1] + len[(o<<1)|1]; } }sgt; int main(){ cin>>n; for(int i=-10000; i<=10000; i++) num[++m] = i; for(int i=1; i<=n; i++){ scanf("%d %d %d %d", &qwq1, &pwp1, &qwq2, &pwp2); cnt++; li1[cnt] = (Line){qwq1, pwp1, pwp2, 1}; li2[cnt] = (Line){pwp1, qwq1, qwq2, 1}; cnt++; li1[cnt] = (Line){qwq2, pwp1, pwp2, -1}; li2[cnt] = (Line){pwp2, qwq1, qwq2, -1}; } sort(li1+1, li1+1+cnt, cmp); sort(li2+1, li2+1+cnt, cmp); for(int i=1; i<=cnt; i++){ int lst=sgt.len[1]; sgt.update(1, 1, m, li1[i].vv, li1[i].ww, li1[i].id); ans += abs(sgt.len[1]-lst); } for(int i=1; i<=cnt; i++){ int lst=sgt.len[1]; sgt.update(1, 1, m, li2[i].vv, li2[i].ww, li2[i].id); ans += abs(sgt.len[1]-lst); } cout<<ans<<endl; return 0; }

luogu1856 [USACO5.5]矩形周長Picture