zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    删数问题
    八中公司_二分图带权最大匹配模板题
    完美子图(这道题太难了,得写下来要不回头又忘了)
    最近集训的图论(思路+实现)题目汇总(内容包含tarjan、分层图、拓扑、差分、奇怪的最短路):
    方格取数(简单版)+小烈送菜(不知道哪来的题)-----------奇怪的dp增加了!
    单调队列优化题:最大数(P1198)
    单调队列+线性dp题Watching Fireworks is Fun (CF372C)
    关于看了几道洛谷灰题(暂无评定)的感想
    洛谷的奇妙今日运势
    互不侵犯(洛谷P1896)
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/10048084.html
Copyright © 2011-2022 走看看