zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    自己实现 一个 Vue框架,包含了Vue的核心原理
    Vue-Cli 3.0 中配置高德地图的两种方式
    element-ui table 点击某行高亮(修改背景色)
    input type="file"获取文件名方法
    使用 http-proxy-middleware 做转发, post 请求转发失败
    core-js@2 core-js@3报错问题
    VUE判断当前设备是PC还是移动端
    Vue函数式组件 简单实现
    清明节哀悼日网页变黑白色的CSS代码
    Vue实现递归menu
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9857222.html
Copyright © 2011-2022 走看看