专题突破二之优先队列、st表——,Running Median,Sequence,Buy Low Sell High,数据备份,超级钢琴,ZQC的手办
文章目錄
- Running Median
- Sequence
- Buy Low Sell High
- [APIO/CTSC 2007] 數(shù)據(jù)備份
- [NOI2010] 超級鋼琴
- 「LibreOJ β Round」ZQC 的手辦
Running Median
source
對頂棧
用大根堆和小根堆一起維護
- 若元素小于等于大根堆棧頂,放入大根堆
- 否則放入小根堆
大根堆維護的就是前一半較小的樹,小根堆維護的就是后一半較大的樹
最后調(diào)整兩個堆的大小(大根堆比小根堆多一)
答案就是大根堆的棧頂
#include <cstdio> #include <queue> using namespace std; #define maxn 10000 priority_queue < int > MS; priority_queue < int, vector < int >, greater < int > > IS; int x[maxn];int main() {int T, Case, n;scanf( "%d", &T );while( T -- ) {while( ! MS.empty() ) MS.pop();while( ! IS.empty() ) IS.pop();scanf( "%d %d", &Case, &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &x[i] );int cnt = 0;printf( "%d %d\n", Case, ( n + 1 ) >> 1 );for( int i = 1;i <= n;i ++ ) {if( MS.empty() || x[i] < MS.top() ) MS.push( x[i] );else IS.push( x[i] );if( i & 1 ) {while( IS.size() < ( i >> 1 ) )IS.push( MS.top() ), MS.pop();while( MS.size() < ( ( i + 1 ) >> 1 ) )MS.push( IS.top() ), IS.pop();cnt ++, printf( "%d ", MS.top() );if( cnt == 10 ) printf( "\n"), cnt = 0;}}printf( "\n" );}return 0; }Sequence
source
先把每行的mmm個元素排序
一層一層的往下疊加,僅保留前mmm小即可
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define maxn 2005 priority_queue < int > q; int T, n, m; int now[maxn], nxt[maxn];int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &n, &m );for( int i = 1;i <= m;i ++ )scanf( "%d", &now[i] );sort( now + 1, now + m + 1 );for( int k = 1;k < n;k ++ ) {for( int i = 1;i <= m;i ++ )scanf( "%d", &nxt[i] );sort( nxt + 1, nxt + m + 1 );for( int i = 1;i <= m;i ++ )for( int j = 1;j <= m;j ++ ) {int val = now[i] + nxt[j];if( q.size() == m && ! q.empty() && val >= q.top() ) break;else {q.push( val );while( q.size() > m ) q.pop();}}for( int i = 1;i <= m;i ++ )now[m - i + 1] = q.top(), q.pop();}for( int i = 1;i <= m;i ++ )printf( "%d ", now[i] );printf( "\n" );}return 0; }Buy Low Sell High
source
反悔貪心
如果第iii天的收益更好,那么彈出棧頂,選擇第iii天
e.g.
k→j→ik\rightarrow j\rightarrow ik→j→i,最優(yōu)選擇為k→ik\rightarrow ik→i
在當前最優(yōu)解的jjj時,選擇k→jk\rightarrow jk→j先記錄臨時答案,然后把jjj的股票價放進棧
在iii的時候進行pi?pjp_i-p_jpi??pj?,剛好抵消 pj?pk+pi?pj=pi?pkp_j-p_k+p_i-p_j=p_i-p_kpj??pk?+pi??pj?=pi??pk?
#include <cstdio> #include <queue> using namespace std; #define int long long #define maxn 300005 priority_queue < int, vector < int >, greater < int > > q; int n, ans; int p[maxn];signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &p[i] );for( int i = 1;i <= n;i ++ ) {if( ! q.empty() && q.top() < p[i] )ans += p[i] - q.top(), q.pop(), q.push( p[i] );q.push( p[i] );}printf( "%lld\n", ans );return 0; }[APIO/CTSC 2007] 數(shù)據(jù)備份
source
反悔貪心
選了iii就不能選i?1,i+1i-1,i+1i?1,i+1
彌補的代價為di?1+di+1?did_{i-1}+d_{i+1}-d_idi?1?+di+1??di?
雙向鏈表維護
#include <queue> #include <cstdio> #include <iostream> using namespace std; #define maxn 100005 #define int long long struct node {int id, l, r, val;node(){}node( int ID, int L, int R, int Val ) {id = ID, l = L, r = R, val = Val;} }it[maxn]; struct Node {int id, val;Node(){}Node( int ID, int Val ) {id = ID, val = Val;}bool operator < ( Node t ) const {return val > t.val;} }; priority_queue < Node > q; int n, k, ans; bool vis[maxn];void Delete( int x ) {it[x].l = it[it[x].l].l;it[x].r = it[it[x].r].r;it[it[x].l].r = x;it[it[x].r].l = x; }signed main() {int last;scanf( "%lld %lld %lld", &n, &k, &last );for( int i = 1, d;i < n;i ++ ) {scanf( "%lld", &d );it[i] = node( i, i - 1, i + 1, d - last );q.push( Node( i, d - last ) );last = d;}it[0].val = it[n].val = 1e15;for( int i = 1;i <= k;i ++ ) {while( vis[q.top().id] ) q.pop(); int val = q.top().val, x = q.top().id;q.pop(), ans += val;vis[it[x].l] = vis[it[x].r] = 1;it[x].val = it[it[x].l].val + it[it[x].r].val - it[x].val;q.push( Node( x, it[x].val ) );Delete( x );}printf( "%lld\n", ans );return 0; }[NOI2010] 超級鋼琴
source
對于每個iii,將其符合要求的區(qū)間扔進隊列,確定最大值的位置pospospos
可以使用ststst表預處理最大值位置
然后大根堆,開始選擇
一段區(qū)間最大值知曉了,次大值一定是在最大值的左邊或者右邊(刨除最大值位置)
所以直接將區(qū)間劃成兩部分扔進大根堆,要保證區(qū)間存在
#include <iostream> #include <cstdio> #include <queue> #include <cmath> using namespace std; #define maxn 500005 int n, k, L, R; int sum[maxn]; int st[maxn][20];void init() {for( int i = 1;i <= n;i ++ ) st[i][0] = i;for( int j = 1;j < 20;j ++ )for( int i = 1;i + ( 1 << j ) - 1 <= n;i ++ )if( sum[st[i + ( 1 << j - 1 )][j - 1]] > sum[st[i][j - 1]] )st[i][j] = st[i + ( 1 << j - 1 )][j - 1];elsest[i][j] = st[i][j - 1]; }int query( int l, int r ) {int i = log2( r - l + 1 );if( sum[st[l][i]] >= sum[st[r - ( 1 << i ) + 1][i]] )return st[l][i];elsereturn st[r - ( 1 << i ) + 1][i]; }struct node {int s, l, r, t;node( int S, int L, int R ) { s = S, l = L, r = R, t = query( l, r ); }bool operator < ( node MS ) const { return sum[t] - sum[s - 1] < sum[MS.t] - sum[MS.s - 1]; } }; priority_queue < node > q;int main() {scanf( "%d %d %d %d", &n, &k, &L, &R );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &sum[i] );sum[i] += sum[i - 1];}init();for( int i = 1;i <= n - L + 1;i ++ )q.push( node( i, i + L - 1, min( i + R - 1, n ) ) );long long ans = 0;while( k -- ) {node now = q.top(); q.pop();ans += sum[now.t] - sum[now.s - 1];if( now.t != now.l ) q.push( node( now.s, now.l, now.t - 1 ) );if( now.t != now.r ) q.push( node( now.s, now.t + 1, now.r ) );}printf( "%lld\n", ans );return 0; }「LibreOJ β Round」ZQC 的手辦
source
超級鋼琴的父版
操作111直接線段樹標記維護
操作222因為保證xxx總和不會很大,那么類似超級鋼琴一樣將區(qū)間切成兩部分那種
用線段樹查區(qū)間最小值以及最小值位置
#include <queue> #include <cstdio> #include <iostream> using namespace std; #define maxn 500005 #define inf 0x7f7f7f7f #define lson num << 1 #define rson num << 1 | 1 #define Pair pair < int, int > void read(int &x) {x = 0;char s = getchar();while (s < '0' || s > '9')s = getchar();while ('0' <= s && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48);s = getchar();} } struct node {int l, r;Pair ret;node() {}node(int L, int R, Pair p) {l = L, r = R, ret = p;}bool operator < (const node &t) const {return ret.first > t.ret.first;} }; priority_queue < node > q; int a[maxn], ans[maxn]; int t[maxn << 2], pos[maxn << 2], tag[maxn << 2];void pushup(int num) {if (t[lson] <= t[rson])t[num] = t[lson], pos[num] = pos[lson];elset[num] = t[rson], pos[num] = pos[rson]; }void build(int num, int l, int r) {if (l == r) {t[num] = a[l];pos[num] = l;return;}int mid = (l + r) >> 1;build(lson, l, mid);build(rson, mid + 1, r);pushup(num); }void pushdown(int num) {t[lson] = max(t[lson], tag[num]);t[rson] = max(t[rson], tag[num]);tag[lson] = max(tag[lson], tag[num]);tag[rson] = max(tag[rson], tag[num]);tag[num] = 0; }void modify(int num, int l, int r, int L, int R, int k) {if (t[num] >= k)return;if (R < l || r < L)return;if (L <= l && r <= R) {t[num] = max(t[num], k);tag[num] = max(tag[num], k);return;}pushdown(num);int mid = (l + r) >> 1;modify(lson, l, mid, L, R, k);modify(rson, mid + 1, r, L, R, k);pushup(num); }Pair query(int num, int l, int r, int L, int R) {if (r < L || R < l)return make_pair(inf, inf);if (L <= l && r <= R)return make_pair(t[num], pos[num]);pushdown(num);int mid = (l + r) >> 1;Pair ans1 = query(lson, l, mid, L, R);Pair ans2 = query(rson, mid + 1, r, L, R);if (ans1.first <= ans2.first)return ans1;elsereturn ans2; }int main() {int n, m;read(n);for (int i = 1; i <= n; i ++)read(a[i]);build(1, 1, n);read(m);for (int i = 1, opt, a, b, k, x; i <= m; i ++) {read(opt), read(a), read(b), read(k);if (opt & 1)modify(1, 1, n, a, b, k);else {read(x);while (! q.empty())q.pop();int cnt = 0;q.push(node(a, b, query(1, 1, n, a, b)));while (! q.empty() && cnt < x) {node now = q.top();q.pop();int val = now.ret.first, pos = now.ret.second;if (val >= k)break;elseans[++ cnt] = val;if (pos != now.l)q.push(node(now.l, pos - 1, query(1, 1, n, now.l, pos - 1)));if (pos != now.r)q.push(node(pos + 1, now.r, query(1, 1, n, pos + 1, now.r)));}if (cnt < x)printf("-1\n");else {for (int i = 1; i <= x; i ++)printf("%d ", ans[i]);printf("\n");}}}return 0; }總結
以上是生活随笔為你收集整理的专题突破二之优先队列、st表——,Running Median,Sequence,Buy Low Sell High,数据备份,超级钢琴,ZQC的手办的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宏碁 10 月营收 193.5 亿新台币
- 下一篇: 新封神榜演员表 新封神榜演员有谁