UVALive - 4108 SKYLINE (吉司机线段树)

题目链接

题意:在一条直线上依次建造n座建筑物,每座建筑物建造完成后询问它在多长的部分是最高的。

比较好想的方法是用线段树分别维护每个区间的最小值mi和最大值mx,当建造一座高度为x的建筑物时,若mi>x则答案无贡献,直接退出,若mx<=x则区间赋值为x,答案加上区间长度。其他情况需要继续递归搜索。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e5+10,inf=0x3f3f3f3f;
 5 int n,mx[N<<2],mi[N<<2],lz[N<<2];
 6 ll ans;
 7 #define ls (u<<1)
 8 #define rs (u<<1|1)
 9 #define mid ((l+r)>>1)
10 void pu(int u) {mx[u]=max(mx[ls],mx[rs]),mi[u]=min(mi[ls],mi[rs]);}
11 void change(int u,int x) {mx[u]=mi[u]=lz[u]=x;}
12 void pd(int u) {if(~lz[u])change(ls,lz[u]),change(rs,lz[u]),lz[u]=-1;}
13 void build(int u=1,int l=1,int r=100000) {
14     lz[u]=-1;
15     if(l==r) {mx[u]=mi[u]=0; return;}
16     build(ls,l,mid),build(rs,mid+1,r),pu(u);
17 }
18 void upd(int L,int R,int x,int u=1,int l=1,int r=100000) {
19     if(l>R||r<L||x<mi[u])return;
20     if(l>=L&&r<=R&&x>=mx[u]) {ans+=r-l+1,change(u,x); return;}
21     pd(u),upd(L,R,x,ls,l,mid),upd(L,R,x,rs,mid+1,r),pu(u);
22 }
23 int main() {
24     int T;
25     for(scanf("%d",&T); T--;) {
26         build(),ans=0;
27         scanf("%d",&n);
28         while(n--) {
29             int l,r,x;
30             scanf("%d%d%d",&l,&r,&x),r--;
31             upd(l,r,x);
32         }
33         printf("%lld\n",ans);
34         scanf(" 0");
35     }
36     return 0;
37 }

这种方法对于随机数据是比较快的,但会被一些极端的数据卡成n^2,比如先来个[1,2,100000],[3,4,100000],...(每两个位置建一座很高的建筑物),然后来一堆[1,100000,1],[1,100000,2],...,遇到这种情况就GG了。

解决方法是改成吉司机线段树(Segment tree beats),稳定nlogn~

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e5+10,inf=0x3f3f3f3f;
 5 int n,mi[N<<2],se[N<<2],nmi[N<<2],lz[N<<2];
 6 ll ans;
 7 #define ls (u<<1)
 8 #define rs (u<<1|1)
 9 #define mid ((l+r)>>1)
10 void pu(int u) {
11     mi[u]=min(mi[ls],mi[rs]),se[u]=max(mi[ls],mi[rs]);
12     se[u]=se[u]==mi[u]?min(se[ls],se[rs]):min(se[u],min(se[ls],se[rs]));
13     nmi[u]=(mi[ls]==mi[u]?nmi[ls]:0)+(mi[rs]==mi[u]?nmi[rs]:0);
14 }
15 void change(int u,int x) {mi[u]=lz[u]=x;}
16 void pd(int u) {
17     if(~lz[u]) {
18         if(mi[ls]<lz[u])change(ls,lz[u]);
19         if(mi[rs]<lz[u])change(rs,lz[u]);
20         lz[u]=-1;
21     }
22 }
23 void build(int u=1,int l=1,int r=100000) {
24     lz[u]=-1;
25     if(l==r) {mi[u]=0,se[u]=inf,nmi[u]=1; return;}
26     build(ls,l,mid),build(rs,mid+1,r),pu(u);
27 }
28 void upd(int L,int R,int x,int u=1,int l=1,int r=100000) {
29     if(l>R||r<L||mi[u]>x)return;
30     if(l>=L&&r<=R&&se[u]>x) {change(u,x),ans+=nmi[u]; return;}
31     pd(u),upd(L,R,x,ls,l,mid),upd(L,R,x,rs,mid+1,r),pu(u);
32 }
33 int main() {
34     int T;
35     for(scanf("%d",&T); T--;) {
36         build(),ans=0;
37         scanf("%d",&n);
38         while(n--) {
39             int l,r,x;
40             scanf("%d%d%d",&l,&r,&x),r--;
41             upd(l,r,x);
42         }
43         scanf(" 0");
44         printf("%lld\n",ans);
45     }
46     return 0;
47 }

 

posted @ 2019-04-26 16:46  jrltx  阅读(326)  评论(0编辑  收藏  举报