zoukankan      html  css  js  c++  java
  • bzoj1367: [Baltic2004]sequence

    首先先减下标转换成求最长不下降子序列(是个套路?见了几次还是不是很懂)

    然后对于递增的直接取值就可以了,递减就来个中位数

    可以构造出一个这样的算法:

    每次插入一个新的区间[i,i],使用a[i],表示当前点最好用自己的值就可以了

    和前一个区间比较,如果这个点选用的值较小,进行区间合并,这个区间用它的中位数

    那么就是动态询问区间中位数了,这个可以上主席树搞??

    看到题解的大佬们都是上高贵的野兽可并堆,YY一下其实也简单,就是维护区间一半的数嘛

    唯一有点玄学的是,维护区间较大的一半数会WA穿,要维护较小一半的数

    原因:假如是较大的数,前面有可能有大量大数导致去掉了前面的大数而令后面的小一点的数被保留,而后面不可能有超过一半的数比前面的最大数要大否则后面的中位数一定会大于前面。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    int cnt,L[1100000],R[1100000];
    struct heap{int lc,rc,dep,tot;LL c;}h[1100000];int len,rt[1100000];
    void add(int x,LL d)
    {
        len++;
        h[len].lc=h[len].rc=0;h[len].c=d;
        h[len].dep=1;h[len].tot=1;
        
        rt[++cnt]=len;
        L[cnt]=R[cnt]=x;
    }
    int merge(int x,int y)
    {
        if(x==0||y==0)return x+y;
        if(h[x].c<h[y].c)swap(x,y);
        
        h[x].tot+=h[y].tot;
        h[x].rc=merge(h[x].rc,y);
        if(h[h[x].lc].dep<h[h[x].rc].dep)swap(h[x].lc,h[x].rc);
        h[x].dep=h[h[x].lc].dep+1;
        return x;
    }
    void pop(int x){rt[x]=merge(h[rt[x]].lc,h[rt[x]].rc);}
    void change(int x,int y)
    {
        int num=(R[x]-L[x]+2)/2;//堆里面扔的数个数 
        rt[x]=merge(rt[x],rt[y]);
        while(h[rt[x]].tot>num)pop(x);
    }
    
    LL a[1100000];
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]), a[i]-=i;
        len=0;cnt=0;
        memset(rt,0,sizeof(rt));
        for(int i=1;i<=n;i++)
        {
            add(i,a[i]);
            while(cnt>1&&h[rt[cnt-1]].c>h[rt[cnt]].c)
                cnt--,R[cnt]=R[cnt+1],change(cnt,cnt+1);    
        }
        LL sum=0;
        for(int i=1;i<=cnt;i++)
            for(int j=L[i];j<=R[i];j++)
                sum+=abs(a[j]-h[rt[i]].c);
        printf("%lld
    ",sum);
        
        return 0;
    }
  • 相关阅读:
    【转载】分析商品日均销量(DMS)对促销商品选择的意义
    日志备份和差异备份还原中的常见问题示例(转自&邹建)
    SQL Server 2000中的完整备份、差异备份操作
    数据库差异备份与增量备份的不同之处
    差异备份和还原操作方法(转)
    SQL备份(全)
    Microsoft SQL2000 错误代码 (@@error)
    图解SQL的inner join(join)、left join、right join、full outer join、union、union all的区别
    arm-none-linux-gnueabi-gcc command not found
    关于ST-Link的internal command error问题的解决方法
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10158877.html
Copyright © 2011-2022 走看看