bzoj4662: Snow
调了一早上80pt不知道那里错了。。。结果发现我看错题意了。。。一个清洁工扫的是区间而不是点。。。
先离散化
首先对于一个人它扫了地,他影响的其他人是一个区间
而且每个区间都只会被扫一次,所以我们可以暴力枚举
那么算法的架构已经出来了:线段树维护清洁工清理区间长度的最小值,然后每次选出一个清洁工,就把它扫的区间枚举一次,修改会被影响的其他清洁工
并查集瞎维护一下就可以了。。。今年NOIP才考
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #define mid (ql+qr)/2 #define lc now<<1 #define rc now<<1|1 using namespace std; typedef pair<int,int> pa; const int _=100; const int maxn=3*1e5+_; const int fbin=(1<<19)+_; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } void write(int x) { if(x<0)putchar('-'); if(x>=10)write(x/10); putchar(x%10+'0'); } struct node{int l,r,id;}p[maxn]; bool cmp(node n1,node n2){return n1.l<n2.l;} int lslen,ls[maxn*4],sd[maxn*4]; //----------------------------------def-------------------------------------------------- struct trnode { int mn,id,la; }tr[fbin*2];int z; void update(int now) { if(tr[lc].mn<0){tr[now].mn=tr[rc].mn,tr[now].id=tr[rc].id;return ;} if(tr[rc].mn<0){tr[now].mn=tr[lc].mn,tr[now].id=tr[lc].id;return ;} if((tr[lc].mn<tr[rc].mn||(tr[lc].mn==tr[rc].mn&&tr[lc].id<tr[rc].id))) tr[now].mn=tr[lc].mn,tr[now].id=tr[lc].id; else tr[now].mn=tr[rc].mn,tr[now].id=tr[rc].id; } void pushdown(int now) { if(tr[now].la==0)return ; if(tr[lc].mn!=-1)tr[lc].mn+=tr[now].la,tr[lc].la+=tr[now].la; if(tr[rc].mn!=-1)tr[rc].mn+=tr[now].la,tr[rc].la+=tr[now].la; tr[now].la=0; } //~~~~~~~~in~~~~~~~~~~~ void bt(int now,int ql,int qr) { if(ql==qr){ tr[now].mn=sd[p[ql].r]-sd[p[ql].l],tr[now].id=++z; return ; } else{ bt(lc,ql,mid),bt(rc,mid+1,qr); update(now); } } void change(int now,int ql,int qr,int l,int r,int d) { if(ql==l&&qr==r){tr[now].mn+=d,tr[now].la+=d;return ;} pushdown(now); if(r<=mid) change(lc,ql,mid,l,r,d); else if(mid+1<=l)change(rc,mid+1,qr,l,r,d); else change(lc,ql,mid,l,mid,d),change(rc,mid+1,qr,mid+1,r,d); update(now); } int findmn(int now,int ql,int qr,int p) { if(ql==qr){return tr[now].mn;} pushdown(now); if(p<=mid)return findmn(lc,ql,mid,p); else return findmn(rc,mid+1,qr,p); } //~~~~~~~~~~~out~~~~~~~~~~~~~~~ //-----------------------------------seg---------------------------------------------- int R[maxn*4]; int findR(int x) { if(R[x]==x)return x; R[x]=findR(R[x]);return R[x]; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int T,n; T=read(),n=read(); for(int i=1;i<=n;i++) p[i].l=read(),p[i].r=read(),p[i].id=i; sort(p+1,p+n+1,cmp); for(int i=1;i<=n;i++) ls[++lslen]=p[i].l,ls[++lslen]=p[i].r; sort(ls+1,ls+lslen+1); lslen=unique(ls+1,ls+lslen+1)-ls-1; for(int i=2;i<=lslen;i++) sd[i]=sd[i-1]+ls[i]-ls[i-1]; for(int i=1;i<=n;i++) { p[i].l=lower_bound(ls+1,ls+lslen+1,p[i].l)-ls, p[i].r=lower_bound(ls+1,ls+lslen+1,p[i].r)-ls; } //-------------------------LSH------------------------- bt(1,1,n); for(int i=0;i<=lslen+1;i++)R[i]=i; int x; for(int t=1;t<=n;t++) { x=tr[1].id; write(p[x].id);puts(""); int l,r,st,ed; for(int k=findR(p[x].l+1);k<=p[x].r;R[k]=findR(k+1),k=R[k]) { l=1,r=n,st=n+1; while(l<=r) { int m=(l+r)/2; if(k<=p[m].r)r=m-1,st=m; else l=m+1; } l=1,r=n,ed=0; while(l<=r) { int m=(l+r)/2; if(p[m].l<k)l=m+1,ed=m; else r=m-1; } if(st<=ed) change(1,1,n,st,ed,sd[k-1]-sd[k]); } change(1,1,n,x,x,-1); } return 0; }
pain and happy in the cruel world.