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;
}

 

posted @ 2018-10-26 16:35  AKCqhzdy  阅读(188)  评论(0编辑  收藏  举报