• uoj#29. 【IOI2014】Holiday


    http://uoj.ac/problem/29

    经过的点集一定是一个包含start的区间,为了经过这个区间内所有点,必须先到达一个区间端点,再到达另一个区间端点,剩余的步数则贪心选区间内最大价值的点。显然决策单调,于是可以分治,用可持久化线段树快速求出区间前k大数之和。

    #include"holiday.h"
    #include<cstring>
    #include<algorithm>
    typedef long long i64;
    const int N=500007;
    i64 ans=0;
    int v[N],*vs[N],S,D;
    struct node{
        node*c[2];
        int sz;
        i64 s;
    }ns[N*21],*np=ns,*rt[N];
    i64 kmx(int L,int R,int x){
        node*w1=rt[L],*w2=rt[R+1];
        i64 sum=0;
        for(int i=16;i>=0;--i){
            int s=w1->c[0]->sz-w2->c[0]->sz;
            if(s<=x){
                x-=s;
                sum+=w1->c[0]->s-w2->c[0]->s;
                w1=w1->c[1];
                w2=w2->c[1];
            }else{
                w1=w1->c[0];
                w2=w2->c[0];
            }
        }
        return sum;
    }
    node*ins(node*w,int x,int v){
        node*u=++np,*u0=u;
        for(int i=16;i>=0;--i){
            int d=x>>i&1;
            u->c[d^1]=w->c[d^1];
            u=u->c[d]=++np;w=w->c[d];
            u->sz=w->sz+1;
            u->s=w->s+v;
        }
        return u0;
    }
    void calc1(int L,int R,int l,int r){
        if(L>R)return;
        int M=L+R>>1,m=l,res=D-(S-M)*2-(l-S);
        i64 mv=-1;
        for(int i=l;i<=r&&res>=0;++i,--res){
            i64 v=kmx(M,i,res);
            if(v>mv)mv=v,m=i;
        }
        if(ans<mv)ans=mv;
        calc1(L,M-1,l,m);
        calc1(M+1,R,m,r);
    }
    void calc2(int L,int R,int l,int r){
        if(L>R)return;
        int M=L+R>>1,m=r,res=D-(M-S)*2-(S-r);
        i64 mv=-1;
        for(int i=r;i>=l&&res>=0;--i,--res){
            i64 v=kmx(i,M,res);
            if(v>mv)mv=v,m=i;
        }
        if(ans<mv)ans=mv;
        calc2(L,M-1,l,m);
        calc2(M+1,R,m,r);
    }
    bool cmp(int*a,int*b){
        return *a>*b;
    }
    i64 findMaxAttraction(int n,int start,int d,int attr[]){
        rt[n]=ns->c[0]=ns->c[1]=ns;
        memcpy(v,attr,sizeof(int)*n);
        for(int i=0;i<n;++i)vs[i]=v+i;
        std::sort(vs,vs+n,cmp);
        for(int i=0;i<n;++i)*vs[i]=i;
        for(int i=n-1;i>=0;--i)rt[i]=ins(rt[i+1],v[i],attr[i]);
        D=d;S=start;
        calc1(std::max(0,S-d/2),S,S,n-1);
        calc2(S,std::min(n-1,S+d/2),0,S);
        return ans;
    }
    #include"grader.cpp"
  • 相关阅读:
    5个经典的javascript面试问题
    去年的一些面试题
    各种奇妙的hack
    jQuery工作原理解析以及源代码示例
    JavaScript Window
    原生JavaScript技巧大收集(1~10)
    蜘蛛爬虫类程序抓取有防盗链的网站处理 php和wget命令简单破解防盗链网站的功能
    Git SSH Key 生成步骤
    linux下ssh使用rsa认证教程
    linux FTP服务器 VSFTP配置手册
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7504086.html
Copyright © 2020-2023  润新知