题:http://acm.hdu.edu.cn/showproblem.php?pid=6888
题意:给定n个二维坐标系上的矩形,问每插入一个矩形后这些矩形的周长并是多少(强制在线,1<=n<=1e5,1<=x,y<=1e9,且每个矩形的下边界一定是x轴)。
分析:
- 强条件:每个矩形的下边界一定是x轴,那么就可以把矩形的周长并分为俩部分来算:竖线和横线;
- 对于横线:简单的区间覆盖;
- 由于使1e9,先离散化,预算出每个线段长度,当要更新时就标记信号要用到之前预处理的线段长度,这部分答案*2,因为有上下边界;
- 对于竖线:对于每个被覆盖的位置都有一个值a[i],那么答案就是∑|a[ i ] - a[ i - 1] |;
- 对于每次加进来的一个矩阵,对于竖线部分的影响就是区间取max,这个用jls线段树解决,难点就是在维护jls线段树的同时维护竖线的答案总和;
- 我们发现,在维护区间max时,我们用到了最小值mi和次小值se,让要更新值v在mi<c<se更新,那么那些mi的位置更新成c对答案的影响就是减去c-mi(若这个位置旁边的值不是mi);
- 那么就是在维护取max操作的同时维护这样的“断层”(a[ i ]和a[ i - 1 ]中只有一个是区间的mi)的个数cnt;
- 这个只要知道即将合并的俩个区间的左右端点的a[i]值即可,通过判断左儿子的右断点和右儿子的左端点来使cnt+=0 or 1;
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define lc root<<1 #define rc root<<1|1 typedef long long ll; const int mod=1e9+7; const int M=1e6+6; const int inf=0x3f3f3f3f; const ll INF=1e18; struct QU{ int l,r,h; }q[M]; int tmp[M]; struct JlsSegTree{ struct node{ ll mi,se;///最小值和次小值 ll cnt;///a[i]和a[i+1]之间其中一个是区间mi这样间隔的个数 ll l,r;///左右端点的值 ll len;///离散前区间的长度 ll val1;///区间覆盖 ll val2;///sum(|a[i]-a[i+1]|) int lz; node (){ cnt=l=r=len=val1=val2=mi=se=lz=0; } void Max(ll v){ if(mi >= v) return; l = max(l,v), r = max(r,v); val2 -= cnt * (v-mi); mi = v; } }tr[M<<2]; void up(int root){ tr[root].cnt=0; tr[root].l=tr[lc].l; tr[root].r=tr[rc].r; tr[root].val2=tr[lc].val2+tr[rc].val2; tr[root].mi=min(tr[lc].mi,tr[rc].mi); tr[root].se=min(tr[lc].se,tr[rc].se); if(tr[lc].mi!=tr[rc].mi) tr[root].se=min(tr[root].se,max(tr[lc].mi,tr[rc].mi)); if(tr[root].mi==tr[lc].mi) tr[root].cnt+=tr[lc].cnt; if(tr[root].mi==tr[rc].mi) tr[root].cnt+=tr[rc].cnt; if(tr[lc].r!=tr[rc].l&&(tr[lc].r==tr[root].mi||tr[rc].l==tr[root].mi))///考虑合并的“断层” tr[root].cnt++; tr[root].val2+=abs(tr[lc].r-tr[rc].l); } void pushdown(int root){ tr[lc].Max(tr[root].mi); tr[rc].Max(tr[root].mi); } void build(int root,int l,int r){ tr[root]=node(); if(l==r){ tr[root].se=inf; tr[root].len=tmp[l]-tmp[l-1]; return ; } int midd=(l+r)>>1; build(lson); build(rson); up(root); tr[root].len=tr[lc].len+tr[rc].len; } void update1(int L,int R,int root,int l,int r){///区间覆盖更新 if(L<=l&&r<=R){ tr[root].val1=tr[root].len; tr[root].lz=1; return ; } if(tr[root].lz){ tr[lc].val1=tr[lc].len; tr[rc].val1=tr[rc].len; tr[lc].lz=tr[rc].lz=1; tr[root].lz=0; } int midd=(l+r)>>1; if(L<=midd) update1(L,R,lson); if(R>midd) update1(L,R,rson); tr[root].val1=tr[lc].val1+tr[rc].val1; } void update2(ll v,int L,int R,int root,int l,int r){ if(tr[root].mi>=v) return ; if(L<=l&&r<=R&&tr[root].se>v){ tr[root].Max(v); return ; } int midd=(l+r)>>1; pushdown(root); if(L<=midd) update2(v,L,R,lson); if(R>midd) update2(v,L,R,rson); up(root); } }t1; int main(){ int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); int tot=0; tmp[++tot]=inf; for(int i=1;i<=n;i++){ scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h); tmp[++tot]=q[i].l, tmp[++tot]=q[i].r; } sort(tmp+1,tmp+1+tot); int m=unique(tmp+1,tmp+1+tot)-tmp-1; t1.build(1,1,m); auto getid = [&](int x){ return lower_bound(tmp+1,tmp+1+m,x)-tmp; }; for(int i=1;i<=n;i++){ int posl = getid(q[i].l), posr = getid(q[i].r); t1.update1(posl+1,posr,1,1,m);///区间覆盖更新 t1.update2(q[i].h,posl+1,posr,1,1,m);///a[i]-a[i-1]总和更新 printf("%lld ",2ll*t1.tr[1].val1+t1.tr[1].val2); } } return 0; }