bzoj1367: [Baltic2004]sequence

在z[]单调不减时,中位数贪心,用可合并堆维护区间。

在z[]单调递增时,T[i]=t[i]-i,用上述方法处理。相当于此时求得的z[]虽然单调不减,但在恢复为t时,一定单调递增。

http://www.lydsy.com/JudgeOnline/problem.php?id=1367

/**************************************************************
    Problem: 1367
    User: 1349367067
    Language: C++
    Result: Accepted
    Time:7092 ms
    Memory:28616 kb
****************************************************************/
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
struct Node
{
       int x,dis,size;
       Node *l,*r;
       void clear()
       {
              l=r=NULL;
              dis=0;size=1;
       }
}a[1000011];
bool check_dis(Node *A)
{
     if (A->r==NULL) return false;
     if (A->l==NULL) return true;
     return (A->r->dis>A->l->dis);
       
}
Node *merge(Node *A,Node *B)
{
     if (A==NULL) return B;
     if (B==NULL) return A;
     if (A->x<B->x) swap(A,B);
     A->r=merge(A->r,B);
     if (check_dis(A)) swap(A->l,A->r);
     if (A->r==NULL) A->dis=0;
     else A->dis=A->r->dis+1;
     A->size=1;
     if (A->l!=NULL) A->size+=A->l->size;
     if (A->r!=NULL) A->size+=A->r->size;
     return A;
}
Node *Q[1000011];
int Qs[1000011];
int num=0;
void fix(int i,int n)
{
       
     //cout<<n<<"**"<<endl;
     //system("pause");
     while (Q[i]->size>(n+1)/2)
     {
          //cout<<Q[i]->size<<endl;
          //system("pause");
          Q[i]=merge(Q[i]->l,Q[i]->r);
            
     }
}
inline int abs(int x) {return x<0?(-x):x;}
void init()
{
     for (int i=1;i<=n;i++)
     {
         a[i].clear();
         scanf("%d",&a[i].x);
         a[i].x-=i;
     }
     num=1;Q[1]=&a[1];Qs[0]=0;Qs[1]=1;
     for (int i=2;i<=n;i++)
     {
         num++;
         Q[num]=&a[i];Qs[num]=i;
         while (num>1&&Q[num]->x<Q[num-1]->x)
         {
               Q[num-1]=merge(Q[num],Q[num-1]);
                 
                 
               //cout<<num<<" "<<Qs[num]<<" "<<Qs[num-1]<<endl;
               Qs[num-1]=Qs[num];num--;
               //cout<<num<<"OO"<<endl;
               fix(num,Qs[num]-Qs[num-1]);
                 
               //system("pause");
                 
         }
     }
     long long ans=0ll;
     for (int i=1;i<=num;i++)
     {
         for (int j=Qs[i-1]+1;j<=Qs[i];j++)
         {
             ans+=abs(a[j].x-Q[i]->x);
         }
     }
     //cout<<"*"<<num<<endl;
     //for (int i=1;i<=num;i++)
     //    cout<<Qs[i]<<"*"<<(Q[i]->x)<<" ";
     //cout<<endl;
     printf("%lld\n",ans);
       
}
int main()
{
    scanf("%d",&n);
          init();
            
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/3ZStarve/p/4888133.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值