hdu6888(区间取max,维护连续最小值段数)

题: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\n",2ll*t1.tr[1].val1+t1.tr[1].val2);
        }
    }
    return 0;
}
View Code

 

posted @ 2020-09-22 23:26  starve_to_death  阅读(348)  评论(0编辑  收藏  举报