题目链接
题目大意
题目描述
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;
}