• 1515: PIPI的开关Ⅱ 题解(优先队列维护中位数)


    题目链接

    题目大意

    题目描述

    PIPI得到了n个整数,每个整数下面有两个开关,其中一个开关能使该数+1,而另一个开关能使该数-1。
    现在PIPI想知道,对于每个位置i,使得[1,i]区间的整数变成一段连续的数字,最少需要按多少次开关?
    对于在[1,i)区间的每个j,都满足a[j]+1=a[j+1]的话,那么我们认为[1,i]区间的整数是一段连续的数字。特别得,我们规定当i=1,[1,1]区间的整数也是一段连续的数字。

    输入

    第一行输入一个正整数n,n<=10^5。
    第二行n个整数ai,-10^9 <=ai<=10^9。

    输出

    输出n行,第i行表示将[1,i]区间的整数变成一段连续的数字所要按的最少开关次数。

    题目思路

    思路还是挺简单的令\(a[i]=a[i]-(i-1)\)

    那么就是把\([1,i]\)的所有元素移动到中位数去

    我最开始用优先队列找中位数,然后使用线段树动态开点来维护信息进行计算,可以过但是过于麻烦

    其实可以直接用优先队列顺便维护下两个队列的信息即可

    代码1

    #include<bits/stdc++.h>
    #define int long long
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    const int maxn=2e6+5;
    priority_queue<int,vector<int>,less<int> > p1;
    priority_queue<int,vector<int>,greater<int> > p2;
    int n,k,a[100000+5];
    int mid=-1e9-1e6,cnt=1;
    pair<ll,ll> tree[maxn];
    int lson[maxn],rson[maxn];
    pair<ll,ll> query(int node,ll l,ll r,ll ql,ll qr){
        if(ql>qr) return {0,0};
        if(node==0) return {0,0};
        //这里没有被建树,显然没有值
        if(ql<=l&&r<=qr){
            return tree[node];
        }
        ll mid=(l+r)/2;
        pair<ll,ll> sum={0,0};
        if(mid>=ql) {
            pair<ll,ll> tmp=query(lson[node],l,mid,ql,qr);
            sum.fi+=tmp.fi,sum.se+=tmp.se;
        }
        if(mid<qr){
            pair<ll,ll> tmp =query(rson[node],mid+1,r,ql,qr);
            sum.fi+=tmp.fi,sum.se+=tmp.se;
     
        }
        return sum;
    }
    void update(int &node,ll l,ll r,ll pos){
    //    cout<<l<<" "<<r<<" "<<tree[node].fi<<" "<<tree[node].se<<endl;
        if(node==0) node=++cnt;
        // 引用
        if(l==r){
            tree[node].fi+=l;
            tree[node].se++;
    //        cout<<l<<" "<<tree[node].fi<<" "<<tree[node].se<<endl;
            return ;
        }
        ll mid=(l+r)/2;
        if(mid>=pos){
            update(lson[node],l,mid,pos);
        }else{
            update(rson[node],mid+1,r,pos);
        }
        tree[node].fi=tree[lson[node]].fi+tree[rson[node]].fi;
        tree[node].se=tree[lson[node]].se+tree[rson[node]].se;
    //    cout<<l<<" "<<r<<" "<<tree[node].fi<<" "<<tree[node].se<<endl;
     
    }
    int fd(int x,int i){
        if(x>mid)   p2.push(x);
        else        p1.push(x);
        if(i%2==0)//保证偶数情况 p1.size()=p2.size()
        {
            while(p1.size()>p2.size())
            {
                p2.push(p1.top());
                p1.pop();
            }
            while(p2.size()>p1.size())
            {
                p1.push(p2.top());
                p2.pop();
            }
        }
        else//保证奇数情况 p1.size()+1=p2.size()
        {
            while(p1.size()<p2.size()+1)
            {
                p1.push(p2.top());
                p2.pop();
            }
            while(p1.size()>p2.size()+1)
            {
                p2.push(p1.top());
                p1.pop();
            }
        }
        mid=p1.top();
        return mid;
    }
    signed main(){
    //    cout<<mid<<endl;
    //    cout<<tree[1].se<<endl;
        scanf("%lld",&n);
        int geng=1;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            a[i]+=1e9+1e6;
            a[i]-=(i-1);
            mid=fd(a[i],i);
            update(geng,1,2e9+1e6,a[i]);
            pair<ll,ll> tmp1=query(geng,1,2e9+1e6,1,mid);
            pair<ll,ll> tmp2=query(geng,1,2e9+1e6,mid+1,2e9+1e6);
            ll ans=0;
            ans+=tmp1.se*mid-tmp1.fi+tmp2.fi-tmp2.se*mid;
            printf("%lld\n",ans);
        }
        return 0;
    }
    

    代码2

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<queue>
    using namespace std;
    priority_queue<int,vector<int>,less<int> > p1;
    priority_queue<int,vector<int>,greater<int> > p2;
    int n,x,mid=-1e9-1e6;
    long long cnt1=0,cnt2=0,sum1=0,sum2=0;
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            x-=(i-1);
            if(x>mid){
                cnt2++;
                sum2+=x;
                p2.push(x);
            }else{
                cnt1++;
                sum1+=x;
                p1.push(x);
            }
            if(i%2==0)//保证偶数情况 p1.size()=p2.size()
            {
                while(p1.size()>p2.size())
                {
                    cnt1--;
                    cnt2++;
                    sum1-=p1.top();
                    sum2+=p1.top();
                    p2.push(p1.top());
                    p1.pop();
                }
                while(p2.size()>p1.size())
                {
                    cnt1++;
                    cnt2--;
                    sum1+=p2.top();
                    sum2-=p2.top();
                    p1.push(p2.top());
                    p2.pop();
                }
            }
            else//保证奇数情况 p1.size()=p2.size()+1
            {
                while(p1.size()<p2.size()+1)
                {
                    cnt1++;
                    cnt2--;
                    sum1+=p2.top();
                    sum2-=p2.top();
                    p1.push(p2.top());
                    p2.pop();
                }
                while(p1.size()>p2.size()+1)
                {
                    cnt1--;
                    cnt2++;
                    sum1-=p1.top();
                    sum2+=p1.top();
                    p2.push(p1.top());
                    p1.pop();
                }
            }
            mid=p1.top();
            long long  pr=cnt1*mid-sum1+sum2-cnt2*mid;
            printf("%lld\n",pr);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    app接口开发(php)
    eclipse JRE(unbound)问题
    HTTP状态码详解
    HTTP方法
    项目开发注意事项及技巧
    JavaWeb 路径问题
    POJ 3264 Balanced Lineup(RMQ_ST)
    了解NoSQL
    多表查询(章节摘要)
    ios UITableView 获取点击cell对象
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15855650.html
Copyright © 2020-2023  润新知