BZOJ4662 : Snow
首先离散化,即相邻关键点之间的部分可以压成一段。
注意到区间互不包含,因此排序后每个位置的清理影响到的是一段连续区间的清理工的工作长度。
这显然可以用线段树维护,支持区间减去一个数,单点加上$inf$,以及查询全局最小值。
对于每次清理,暴力枚举区间内所有没清理过的段,在线段树中区间修改,用并查集进行路径压缩即可。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> using namespace std; typedef pair<int,int>P; const int N=300010,M=1050000,inf=1000000010; int n,m,i,j,x,b[N<<1],f[N<<1],tag[M];P v[M];struct E{int l,r;}a[N]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int x,int p){v[x].first+=p;tag[x]+=p;} inline void pb(int x){if(tag[x])add(x<<1,tag[x]),add(x<<1|1,tag[x]),tag[x]=0;} void build(int x,int a,int b){ if(a==b){v[x]=P(::a[a].r-::a[a].l,a);return;} int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); v[x]=min(v[x<<1],v[x<<1|1]); } void del(int x,int a,int b,int c){ if(a==b){v[x].first+=inf;return;} pb(x); int mid=(a+b)>>1; if(c<=mid)del(x<<1,a,mid,c);else del(x<<1|1,mid+1,b,c); v[x]=min(v[x<<1],v[x<<1|1]); } void change(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){add(x,p);return;} pb(x); int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c,d,p); if(d>mid)change(x<<1|1,mid+1,b,c,d,p); v[x]=min(v[x<<1],v[x<<1|1]); } int F(int x){return f[x]==x?x:f[x]=F(f[x]);} inline int lower(int x){ int l=1,r=m,mid,t; while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1; return t; } inline int getl(int c,int d){ int l=1,r=n,mid,t; while(l<=r){ mid=(l+r)>>1; if(a[mid].r<=c)l=mid+1; else if(a[mid].l>=d)r=mid-1; else r=(t=mid)-1; } return t; } inline int getr(int c,int d){ int l=1,r=n,mid,t; while(l<=r){ mid=(l+r)>>1; if(a[mid].r<=c)l=mid+1; else if(a[mid].l>=d)r=mid-1; else l=(t=mid)+1; } return t; } inline void clean(int l,int r){ int x=lower(l); while(1){ x=F(x); if(b[x]>=r)return; f[x]++; change(1,1,n,getl(b[x],b[x+1]),getr(b[x],b[x+1]),b[x]-b[x+1]); } } int main(){ read(n);read(n); for(i=1;i<=n;i++){ read(a[i].l),read(a[i].r); b[++m]=a[i].l,b[++m]=a[i].r; } sort(b+1,b+m+1); for(i=1;i<=m;i++)if(b[i]!=b[i-1])b[++j]=b[i]; m=j; for(i=1;i<=m;i++)f[i]=i; build(1,1,n); for(i=1;i<=n;i++){ x=v[1].second; printf("%d\n",x); del(1,1,n,x); clean(a[x].l,a[x].r); } return 0; }