• P3466 [POI2008]KLO-Building blocks


    题目

    luogu
    csdn好像限制了展开博客次数,真的好xx

    思路

    显然一段区间内的值一定是他的中位数
    少一点比多一点好
    然后就可以枚举区间了
    区间答案为
    val[mid]-小于val[mid]的+大于val[mid]-val[mid]的所有值
    就是size[x]val[mid] - tot_l + tot_r - size[y]val[mid]
    然后你随便写个treap(fhq)就好了

    错误

    一开始siz[x]直接写成mid
    但这是错误的,因为如果有多个数字都等于中位数,那size[x]!=mid
    记得开ll

    代码

    #include <bits/stdc++.h>
    #define FOR(i,a,b) for(int i=a;i<=b;++i)
    #define ll long long
    using namespace std;
    const int maxn=100001;
    int read() {
        int x=0,f=1;char s=getchar();
        for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
        for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
        return x*f;
    }
    int ch[maxn][2],val[maxn],pri[maxn],siz[maxn],sz;
    ll tot[maxn];
    void update(int x) {
        siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
        tot[x]=val[x]+tot[ch[x][0]]+tot[ch[x][1]];
    }
    int new_node(int v) {
        siz[++sz]=1;val[sz]=v;pri[sz]=rand();tot[sz]=v;
        return sz;
    }
    int merge(int x,int y) {
        if(!x||!y) return x+y;
        if(pri[x]<pri[y]) {
            ch[x][1]=merge(ch[x][1],y);
            update(x);
            return x;
        } else {
            ch[y][0]=merge(x,ch[y][0]);
            update(y);
            return y;
        }
    }
    void split(int now,int k,int &x,int &y) {
        if(!now) x=y=0;
        else {
            if(val[now]<=k)
                x=now,split(ch[now][1],k,ch[now][1],y);
            else
                y=now,split(ch[now][0],k,x,ch[now][0]);
            update(now);
        }
    }
    int k_th(int now,int k) {
        while(1) {
            if(k==siz[ch[now][0]]+1)return now;
            if(k<=siz[ch[now][0]]) now=ch[now][0];
            else k-=siz[ch[now][0]]+1,now=ch[now][1];
        }
    }
    int root,n,k,a[maxn];
    void insert(int a) {
        int x,y;
        split(root,a,x,y);
        root=merge(merge(x,new_node(a)),y);
    }
    void delet(int a) {
        int x,y,z;
        split(root,a,x,z);
        split(x,a-1,x,y);
        y=merge(ch[y][0],ch[y][1]);
        root=merge(merge(x,y),z);
    }
    int main() {
        srand(time(NULL));
        n=read(),k=read();
        int mid=(k+1)>>1;
        pair<ll,pair<int,int> > pp;
        pp.first=0x3f3f3f3f3f3f3f3fLL;
        FOR(i,1,n) {
            a[i]=read();
            if(i<k) insert(a[i]);
            else {
                insert(a[i]);
                int x,y,get=k_th(root,mid);
                split(root,val[get],x,y);
                if(pp.first > ((ll)siz[x]*val[get]-(ll)tot[x]+(ll)tot[y]-(ll)siz[y]*val[get])) {
                    pp.first=(ll)siz[x]*val[get]-(ll)tot[x]+(ll)tot[y]-(ll)siz[y]*val[get];
                    pp.second.first=i;
                    pp.second.second=val[get];
                }
                root=merge(x,y);
                delet(a[i-k+1]);
            }
        }
        cout<<pp.first<<"
    ";
        FOR(i,1,n) {
            if(i<=pp.second.first&&i>=pp.second.first-k+1)
                cout<<pp.second.second<<"
    ";
            else
                cout<<a[i]<<"
    ";
        }
        return 0;
    }
    
  • 相关阅读:
    《c程序设计语言》读书笔记-5.8-天数和日期转换错误检查
    《c程序设计语言》读书笔记-5.6-指针重写getline等函数
    《c程序设计语言》读书笔记-5.5-指针实现strncpy,strncat,strncmp
    《c程序设计语言》读书笔记-5.4-指针实现strend
    《c程序设计语言》读书笔记-5.3-指针实现strcat
    《c程序设计语言》读书笔记-4.14-定义宏交换两个参数
    《c程序设计语言》读书笔记-4.13-递归版本reverse函数
    《c程序设计语言》读书笔记-4.12-递归整数转字符串
    递归调用顺序问题
    JavaScript跨站脚本攻击
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/10048084.html
Copyright © 2020-2023  润新知