zoukankan      html  css  js  c++  java
  • sequence(bzoj 1367)

    Description

    Input

    Output

    一个整数R

    Sample Input

    7
    9
    4
    8
    20
    14
    15
    18

    Sample Output

    13

    HINT

    所求的Z序列为6,7,8,13,14,15,18.
    R=13

    /*
      思维很扭曲(反正我想不出来)的一道题。
      先想想不下降的: 
      考虑一个正序的序列,z[i]=t[i] 
      考虑一个逆序的序列,z[i]=x(x是逆列的中位数)
      既然是这样那么我们就可以把整个序列化分成逆序的若干段,对于每段求中位数(正序的可看成num个逆序的)。
      维护中位数用左偏树,具体方法是始终保持堆中数的个数不大于原数个数的一半。
      至于改成上升的,把原序列t[i]-=i。
      
      PS:题解中的root[i]和堆中下标的关系把我看蒙了,所以这里说一下。
          代码中是建立了n个堆,然而不断合并,最终变成了tot个。
          root[i]表示第i个堆(合并后的)的堆顶是哪个元素。 
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #define N 1000010
    using namespace std;
    int t[N],root[N],l[N],r[N],num[N],cnt[N],n,tot;
    struct node{
        int l,r,dis,w;
    };node heap[N];
    int merge(int a,int b){
        if(a==0||b==0)return a+b;
        if(heap[a].w<heap[b].w)swap(a,b);
        heap[a].r=merge(heap[a].r,b);
        if(heap[heap[a].r].dis>heap[heap[a].l].dis)
            swap(heap[a].r,heap[a].l);
        heap[a].dis=heap[heap[a].r].dis+1;
        return a;
    }
    int pop(int a){
        return merge(heap[a].l,heap[a].r);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&t[i]),t[i]-=i;
        for(int i=1;i<=n;i++){
            ++tot;
            l[tot]=r[tot]=i;
            num[tot]=cnt[tot]=1;
            root[tot]=i;
            heap[i].dis=heap[i].l=heap[i].r=0;
            heap[i].w=t[i];
            
            while(tot>1&&heap[root[tot]].w<heap[root[tot-1]].w){
                --tot;
                root[tot]=merge(root[tot],root[tot+1]);
                num[tot]+=num[tot+1],cnt[tot]+=cnt[tot+1],r[tot]=r[tot+1];
                for(;cnt[tot]*2>num[tot]+1;--cnt[tot])
                    root[tot]=pop(root[tot]);
            }
        }
        long long ans=0;
        for(int i=1;i<=tot;i++)
            for(int j=l[i],w=heap[root[i]].w;j<=r[i];j++)
                ans+=abs(t[j]-w);
        cout<<ans;
        return 0;
    } 
  • 相关阅读:
    ACM学习历程—Hihocoder 1288 Font Size(暴力 || 二分)
    ACM学习历程—HDU2476 String painter(动态规划)
    ACM学习历程—BestCoder Round #75
    ACM学习历程—Hihocoder [Offer收割]编程练习赛1
    codeforces 154A 贪心
    分治 最大连续和
    二分 连续上升子序列变形 UVA1471
    POJ3614 贪心+优先队列
    Havel-Hakimi定理 POJ1659
    拓扑排序
  • 原文地址:https://www.cnblogs.com/harden/p/6275078.html
Copyright © 2011-2022 走看看