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了。
解决方法是改成吉司机线段树,稳定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 }
标签:rs,int,void,mi,SKYLINE,UVALive,ls,4108,mx 来源: https://www.cnblogs.com/asdfsag/p/10775169.html