bzoj1805: [Ioi2007]Sail 船帆
可以发现旗杆的顺序是没有用的,对于每列,它的答案是它的最大值mx*(mx+1)/2
高度由小到大排序旗杆,问题可以转化为在前h行选k个最小的值
考虑激情splay乱搞(我只会splay......)
设树中序遍历第i个点的d值表示当前最后一个旗帜上面的数字为i-1的列的数量
我们可以二分一下求出我们要利用到第几个点x,对于x之前的点,他们的d值都要全部送给后一个点
所以我们可以删掉x这个点,并在最前面加一个点,这就相当于整体向右移动了一位
对于x这个点单独处理,删除前计算出留在x的数目和给x+1的数目,处理完以后再单独添加
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct trnode { int f,son[2],c,d,s; }tr[410000];int trlen,root,cnt; void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; tr[x].c=tr[lc].c+tr[rc].c+1; tr[x].s=tr[lc].s+tr[rc].s+tr[x].d; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int R,r; R=f,r=tr[x].son[w]; tr[R].son[1-w]=r; if(r!=0)tr[r].f=R; R=ff,r=x; if(ff!=0) { if(tr[R].son[0]==f)tr[R].son[0]=x; else tr[R].son[1]=x; } tr[r].f=R; R=x,r=f; tr[R].son[w]=r; tr[r].f=R; update(f); update(x); } void splay(int x,int rt) { while(tr[x].f!=rt) { int f=tr[x].f,ff=tr[f].f; if(ff==rt) { if(tr[f].son[0]==x)rotate(x,1); else rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);} else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);} else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);} else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);} } } if(x!=0) { update(x); if(rt==0)root=x; } } //~~~~~~~~~~~~~~~~~~~~~~~in~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int FindFront() { int f=root; while(tr[f].son[0]!=0)f=tr[f].son[0]; return f; } int FindBehind() { int f=root; while(tr[f].son[1]!=0)f=tr[f].son[1]; return f; } int findkth(int k) { int x=root;k++; if(k==0)return 0; while(1) { int lc=tr[x].son[0],rc=tr[x].son[1]; if(tr[lc].c>=k)x=lc; else if(tr[lc].c+1<k)k-=tr[lc].c+1,x=rc; else return x; } } //~~~~~~~~~~~~~~~~~~~~Find~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void add(int d,int f,int w) { int x=++trlen; tr[x].f=f;tr[x].c=1;tr[x].d=d;tr[x].s=d; tr[x].son[0]=tr[x].son[1]=0; if(f!=0)tr[f].son[w]=x; } void InsInFront(int d) { if(root==0)add(d,0,0),root=trlen; else add(d,FindFront(),0); splay(trlen,0); } void InsInBehind(int d) { if(root==0)add(d,0,1),root=trlen; else add(d,FindBehind(),1); splay(trlen,0); } void del(int x) { splay(x,0); if(tr[x].son[0]==0&&tr[x].son[1]==0)root=0; else if(tr[x].son[0]!=0&&tr[x].son[1]==0){root=tr[x].son[0];tr[root].f=0;} else if(tr[x].son[0]==0&&tr[x].son[1]!=0){root=tr[x].son[1];tr[root].f=0;} else { int y=tr[x].son[0]; while(tr[y].son[1]!=0)y=tr[y].son[1]; splay(y,x); int R=y,r=tr[x].son[1]; tr[R].son[1]=r; tr[r].f=R; root=y;tr[root].f=0; update(y); } } //~~~~~~~~~~~~~~~~~~~~~~~out~~~~~~~~~~~~~~~~~~~~~~~~~ //----------------------------------------------------------------------------------------------- LL ans,cc; void dfs(int x) { if(tr[x].son[0]!=0)dfs(tr[x].son[0]); ans+=(cc-1)*cc/2*tr[x].d;cc++; if(tr[x].son[1]!=0)dfs(tr[x].son[1]); } struct node{int h,k;}a[210000]; bool cmp(node n1,node n2){return n1.h<n2.h;} int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].h,&a[i].k); sort(a+1,a+n+1,cmp); a[0].h=0; trlen=0,root=0; tr[0].f=0;tr[0].c=0;tr[0].d=0;tr[0].s=0; tr[0].son[0]=tr[0].son[1]=0; InsInFront(0);cnt=0; for(int i=1;i<=n;i++) { int fr=FindFront(); tr[fr].d+=a[i].h-a[i-1].h; splay(fr,0); int l=0,r=cnt,k; while(l<=r) { int mid=(l+r)/2; int x=findkth(mid);splay(x,0); if(tr[tr[x].son[0]].s+tr[x].d>=a[i].k) { r=mid-1; k=mid; } else l=mid+1; } int x=findkth(k-1);splay(x,0); int s2=a[i].k-tr[tr[x].son[0]].s-tr[x].d;//送给后一个点的值 if(k==cnt)cnt++,InsInBehind(s2); else { int y=findkth(k+1); tr[y].d+=s2;splay(y,0); } x=findkth(k); int s1=tr[x].d-s2;//留给自己的值 del(x);InsInFront(0); x=findkth(k); tr[x].d+=s1;splay(x,0); } ans=0;cc=0;dfs(root); printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.