bzoj1208

权值线段树

这题应该是平衡树,然而可以用权值线段树代替

开2棵权值线段树分别表示有哪些权值的人和有哪些权值的宠物

然后查下前驱和后继就好了

/**************************************************************

    Problem: 1208

    User: syh0313

    Language: C++

    Result: Accepted

    Time:980 ms

    Memory:15236 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <cmath>

#include <algorithm>

#include <map>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int maxn=80010;

const int mo=1000000;

int n,ff[maxn],v[maxn],vv[maxn],linum,topt,root,t;

struct da{int lc,rc,si[2],ma[2],mi[2];}a[maxn*4];

long long ans,line[maxn];

map<int,int>lc;

void build_tree(int &n,int l,int r)

{

    n=++topt; if (l==r) {a[n].si[0]=a[n].si[1]=0; return;}

    int mid=(l+r)>>1;

    build_tree(lch,l,mid); build_tree(rch,mid+1,r);

}

void updata(int n,int k)

{

    a[n].si[k]=a[lch].si[k]+a[rch].si[k];

    a[n].ma[k]=max(a[lch].ma[k],a[rch].ma[k]);

    if (!a[lch].mi[k] && !a[rch].mi[k]) a[n].mi[k]=0;

    if (a[lch].mi[k] && !a[rch].mi[k]) a[n].mi[k]=a[lch].mi[k];

    if (!a[lch].mi[k] && a[rch].mi[k]) a[n].mi[k]=a[rch].mi[k];

    if (a[lch].mi[k] && a[rch].mi[k]) a[n].mi[k]=min(a[lch].mi[k],a[rch].mi[k]);

}

void tree_add(int n,int l,int r,int lc,int k,int kk)

{

    if (l==r)

    {

        a[n].si[kk]+=k;

        if (a[n].si[kk]>0) a[n].ma[kk]=a[n].mi[kk]=l;

        if (a[n].si[kk]==0) a[n].ma[kk]=a[n].mi[kk]=0;

        return;

    }

    int mid=(l+r)>>1;

    if (lc<=mid) tree_add(lch,l,mid,lc,k,kk);

     else tree_add(rch,mid+1,r,lc,k,kk);

    updata(n,kk);

}

int qpre(int n,int L,int R,int l,int r,int kk)

{

    if (!a[n].si[kk]) return 0;

    if (L==l && R==r) return a[n].ma[kk];

    int mid=(L+R)>>1;

    if (r<=mid) return qpre(lch,L,mid,l,r,kk);

    else if (l>=mid+1) return qpre(rch,mid+1,R,l,r,kk);

    else return max(qpre(lch,L,mid,l,mid,kk),qpre(rch,mid+1,R,mid+1,r,kk));

}

int qnxt(int n,int L,int R,int l,int r,int kk)

{

    if (!a[n].si[kk]) return 0;

    if (L==l && R==r) return a[n].mi[kk];

    int mid=(L+R)>>1;

    if (r<=mid) return qnxt(lch,L,mid,l,r,kk);

    else if (l>=mid+1) return qnxt(rch,mid+1,R,l,r,kk);

    else

    {

        int k1=qnxt(lch,L,mid,l,mid,kk),k2=qnxt(rch,mid+1,R,mid+1,r,kk);

        if (!k1 && !k2) return 0;

        if (k1 && !k2) return k1;

        if (!k1 && k2) return k2;

        return min(k1,k2);

    }

}

int main()

{

    scanf("%d",&n);

    for (int i=1;i<=n;i++) scanf("%d%d",&ff[i],&v[i]),vv[i]=v[i];

    sort(vv+1,vv+n+1);

    for (int i=1;i<=n;i++) if (!lc[vv[i]]) lc[vv[i]]=++linum,line[linum]=vv[i];

    build_tree(root,1,linum);

    for (int i=1;i<=n;i++)

    {

        tree_add(root,1,linum,lc[v[i]],1,ff[i]);

        if (a[root].si[0]>=a[root].si[1])

        {

            if (!a[root].si[1]) continue;

            int k=qpre(root,1,linum,1,linum,1);

            int x1=qpre(root,1,linum,1,k,0),x2=qnxt(root,1,linum,k,linum,0);

            if (x1==0)

             {ans+=abs(line[k]-line[x2]); tree_add(root,1,linum,x2,-1,0);}

            else if (x2==0)

             {ans+=abs(line[k]-line[x1]); tree_add(root,1,linum,x1,-1,0);}

            else

            {

                if (line[k]-line[x1]<=line[x2]-line[k])

                 {ans+=abs(line[k]-line[x1]); tree_add(root,1,linum,x1,-1,0);}

                else

                 {ans+=abs(line[k]-line[x2]); tree_add(root,1,linum,x2,-1,0);}

            }

            tree_add(root,1,linum,k,-1,1); ans%=mo;

        }

        else

        {

            if (!a[root].si[0]) continue;

            int k=qpre(root,1,linum,1,linum,0);

            int x1=qpre(root,1,linum,1,k,1),x2=qnxt(root,1,linum,k,linum,1);

            if (x1==0)

             {ans+=abs(line[k]-line[x2]); tree_add(root,1,linum,x2,-1,1);}

            else if (x2==0)

             {ans+=abs(line[k]-line[x1]); tree_add(root,1,linum,x1,-1,1);}

            else

             {

                if (line[k]-line[x1]<=line[x2]-line[k])

                 {ans+=abs(line[k]-line[x1]); tree_add(root,1,linum,x1,-1,1);}

                else

                 {ans+=abs(line[k]-line[x2]); tree_add(root,1,linum,x2,-1,1);}

             }

            tree_add(root,1,linum,k,-1,0); ans%=mo;

        }

    }

    printf("%lld\n",ans);

return 0;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值