IOI Holiday


分治,函数式线段树,题解去问大神吧。。。

提交地址:http://uoj.ac/problem/29【似乎没有vjudge】


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include "holiday.h"
#define c(x,y)  tree[x].c[y]
#define Sum(x)  tree[x].sum
#define Num(x)  tree[x].num 

const int MAXN = 100005,SIZE = 2200000 , MAXD = (MAXN<<1) + (MAXN>>1) + 5;

int n , nl ,st;long long ans = 0;

struct treenode{long long sum;int c[2],num;}tree[SIZE] = {0};
int tot = 0 , root[MAXN] = {0};

int w[MAXN] = {0} , *lixed ,lix[MAXN] = {0},fin[MAXN] = {0};
long long fw[2][MAXD] = {0},gw[2][MAXD] = {0};

inline void update(int x)
{Num(x) = Num(c(x,0)) + Num(c(x,1)) , Sum(x) = Sum(c(x,0)) + Sum(c(x,1));}

int build0(int ll,int rr)
{
    int ret = ++tot ;

    if(ll != rr)
    {
     int mid = (ll+rr)>>1;

     if(ll<=mid){c(ret,0) = build0(ll,mid);}
     if(mid<rr){c(ret,1) = build0(mid+1,rr);}
    }
    return ret;
}

int build1(int ki,int ll,int rr,int si)
{
    int ret = ++tot;

    if(ll == rr){Num(ret) = Num(si) + 1,Sum(ret) = Sum(si) + lix[ki];}
    else
    {
     int mid = (ll+rr)>>1;bool i = (mid<ki);

     if(i)c(ret,i) = build1(ki,mid+1,rr,c(si,i));
     else c(ret,i) = build1(ki,ll,mid,c(si,i));

     c(ret,i^1) = c(si,i^1);   update(ret);
    }
    return ret;
}
void buildtree()
{
    root[0] = build0(1,nl);

    for(int i = 1; i <= n; i++)
     root[i] = build1(fin[i],1,nl,root[i-1]);

    return ; 
}
long long ask(int r1,int r2,int k)
{
    if(k < 0)return 0;
    if(k >= Num(r2) - Num(r1)) return (Sum(r2) - Sum(r1));

    long long ret = 0;
    int num1; long long sum1;
    int ll = 1, rr = nl , mid;

    while(k)
    {
        if(ll == rr)
        {ret += lix[ll]*k;break;}

        num1 = Num(c(r2,1)) - Num(c(r1,1));
        sum1 = Sum(c(r2,1)) - Sum(c(r1,1));
        mid = (ll + rr)>>1;

        if(k < num1)
        {
            r1 = c(r1,1), r2 = c(r2,1); ll = mid+1;
        }
        else
        {
            k -=num1; ret += sum1;
            r1 = c(r1,0), r2 = c(r2,0); rr = mid;
        }
    }
    return ret;
}
void right(int l,int r,int fl,int fr,int tag)
{
    int mid = (l + r)>>1 ,fi = fl;

    for(int i = fl; i <= fr; i++)
     {
        long long tmp = ask(root[st-1],root[i],mid - (i-st)*(tag+1));
        if(tmp > fw[tag][mid]) {fi = i , fw[tag][mid] = tmp;}
     }     
    if(l<mid)right(l,mid-1,fl,fi,tag);
    if(mid<r)right(mid+1,r,fi,fr,tag); 
}
void left(int l,int r,int gl,int gr,int tag)
{
    int mid = (l + r)>>1 ,gi = gl;

    for(int i = gl; i <= gr; i++)
     {
        long long tmp = ask(root[i-1],root[st-1],mid - (st-i)*(tag+1));
        if(tmp > gw[tag][mid]) {gi = i , gw[tag][mid] = tmp;}
     }
    if(l<mid)left(l,mid-1,gi,gr,tag);
    if(mid<r)left(mid+1,r,gl,gi,tag); 
}
long long int findMaxAttraction(int n0, int st0, int d, int att[])
{
    n = n0, st = st0 + 1;w[0] = 0;
    for(int i = 0; i < n ; i++)w[i+1] = att[i];
    for(int i = 1; i <= n ; i++)lix[i] = w[i];

    std::sort(lix+1, lix+n+1); 
    lixed = std::unique(lix+1,lix+n+1);
    nl = lixed - (lix+1);

    for(int i = 1; i <= n ; i++)
      fin[i] = std::lower_bound(lix+1,lix+nl+1,w[i]) - lix;  

    buildtree();

    left(1,d,1,st-1,0);
    left(1,d,1,st-1,1);
    right(1,d,st,n,0);
    right(1,d,st,n,1); 

//    ans = std::max(fw[0][d],fw[1][d]);
    for(int i = 0 ; i <= d ; i++)
    {
        ans = std::max(ans,fw[1][i] + gw[0][d-i]);
        ans = std::max(ans,gw[1][i] + fw[0][d-i]);
    }
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
08-11 1112
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值