P3871 [TJOI2010]中位數(對頂堆)
阿新 • • 發佈:2022-03-30
題意
給定一個N個元素組成的整數序列,有兩種操作:
1.add a 在該序列的最後新增一個整數a,新序列長度為n+1
2.mid 輸出當前序列的中位數
輸入格式
第一行為初始序列長度N。
第二行為N個整數,表示整數序列,數字之間用空格分隔。
第三行為運算元M,即要進行M次操作。
下面為M行,每行輸入格式如題意所述。
輸出格式
對於每個mid操作輸出中位數的值
樣例
input
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
output
5
13
思路
開兩個優先佇列,對頂堆。
從小到大排列的1~n/2的元素實時維護在第一個優先佇列(從大到小)中,剩下的元素維護在第二個優先佇列(從小到大)中。
當然也可以平衡樹啦(Orz)
code
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; //#pragma GCC optimize(3) #define pb push_back #define is insert #define PII pair<int,int> #define show(x) cerr<<#x<<" : "<<x<<endl; //mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count()); //ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);} const int INF=0x3f3f3f3f;//2147483647; const int N=1e5+50,M=1e5+50; const ll mod=998244353; int n; int a[N]; int m; int mid; priority_queue<int>ql; priority_queue<int,vector<int>,greater<int>>qr; void solve() { cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+1+n); cin>>m; int pos; if(n&1){ mid=a[n/2+1]; pos=n/2+1; } else { mid=min(a[n/2],a[n/2+1]); if(a[n/2]<=a[n/2+1]){ pos=n/2; } else { pos=n/2+1; } } for(int i=1;i<=pos;i++){ ql.push(a[i]); } for(int j=pos+1;j<=n;j++){ qr.push(a[j]); } while(m--){ string s;cin>>s; if(s[0]=='a'){ int tmp;cin>>tmp; n++; if(tmp>mid){ qr.push(tmp); } else { ql.push(tmp); } if(n&1){ while(ql.size()>qr.size()){ int tmp=ql.top(); ql.pop(); qr.push(tmp); } while(ql.size()<qr.size()){ int tmp=qr.top(); qr.pop(); ql.push(tmp); } mid=ql.top(); } else { while(ql.size()>qr.size()){ int tmp=ql.top(); ql.pop(); qr.push(tmp); } while(ql.size()<qr.size()){ int tmp=qr.top(); qr.pop(); ql.push(tmp); } int q1=ql.top();int q2=qr.top(); if(q1<=q2){ mid=q1; } else { mid=q2; } } } else { cout<<mid<<"\n"; } //cout<<"mid="<<mid<<endl; } } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int __=1;//cin>>__; while(__--){ solve(); } return 0; }