栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数
文章目錄
- Weak in the Middle
- source
- solution
- code
- Cutting Plants
- source
- solution
- code
- [HNOI2016]最小公倍數(shù)
- source
- solution
- code
Weak in the Middle
source
solution
棧模擬。
天數(shù)的計(jì)算,可以發(fā)現(xiàn)與其參與三元比較的次數(shù)有關(guān)
對(duì)于棧頂,如果被彈出,那么天數(shù)就是max?(\max(max(棧頂?shù)膮⑴c次數(shù),棧中棧頂?shù)南乱粋€(gè)的參與次數(shù))+1)+1)+1
code
#include <cstdio> #include <iostream> using namespace std; #define maxn 100005 int T, n; int sta[maxn], cnt[maxn], ans[maxn], x[maxn];int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &x[i] );ans[i] = cnt[i] = 0;}int top = 0;for( int i = 1;i <= n;i ++ ) {while( top > 1 && x[sta[top]] < x[sta[top - 1]] && x[sta[top]] < x[i] ) {ans[sta[top]] = max( cnt[sta[top - 1]], cnt[sta[top]] ) + 1;cnt[sta[top - 1]] = ans[sta[top]];top --;}sta[++ top] = i;}for( int i = 1;i <= n;i ++ )printf( "%d ", ans[i] );}return 0; }Cutting Plants
source
solution
考場上調(diào)一個(gè)取反符號(hào)調(diào)完正常,非常好
非常標(biāo)準(zhǔn)的分塊可做 只不過實(shí)現(xiàn)。。。
首先,先判無解,必須每棵樹的目標(biāo)高度要小于等于高度
把nnn棵樹分成n\sqrt nn?塊
O(n)O(n)O(n)線性枚舉iii,強(qiáng)制要求該操作后至少第iii個(gè)都必須達(dá)到目標(biāo)要求
相當(dāng)于固定操作的區(qū)間左端點(diǎn)iii,貪心的,想盡可能右移區(qū)間右端點(diǎn)
-
先從iii開始暴力掃一遍iii?所在的塊,并把標(biāo)記tagtagtag下放
-
符合要求:所有樹的目標(biāo)高度都小于等于iii的目標(biāo)高度 且 所有樹的當(dāng)前高度都大于等于iii目標(biāo)高度,這樣才能操作
-
從下一塊開始整塊枚舉
為了直接判斷整塊是否符合要求
用maxxmaxxmaxx記錄塊中所有樹的目標(biāo)高度的最大值
hhh?記錄塊中所有的現(xiàn)在高度的最小值
滿足bi≥maxxj,bi≤hjb_i\ge maxx_j,b_i\le h_jbi?≥maxxj?,bi?≤hj?
-
滿足要求
更新整塊的信息,所有樹的當(dāng)前高度都變成bib_ibi?,用tagtagtag記錄整塊被操作后的同一高度
-
否則,在當(dāng)前塊break
再從當(dāng)前塊頭開始暴力遍歷該塊,tagtagtag下放,可能當(dāng)前塊的前一部分是滿足操作條件的,暴力操作更新
-
-
-
不符合要求,更新到符合要求的最后一棵樹就return
更新:將jjj樹的現(xiàn)在高度,直接變成iii的目標(biāo)高度;更新塊的所有樹的現(xiàn)在高度的最小值
-
code
#include <cmath> #include <cstdio> #include <iostream> using namespace std; #define maxn 100005 #define maxB 320 int T, n, B; int a[maxn], b[maxn], block[maxn], maxx[maxB], tag[maxB], h[maxB];void modify( int pos ) {int End = 0;if( tag[block[pos]] ) {for( int i = pos;i <= min( n, B * block[pos] );i ++ )a[i] = tag[block[pos]];tag[block[pos]] = 0;}for( int i = pos;i <= min( n, B * block[pos] );i ++ )if( a[i] < b[pos] || b[pos] < b[i] ) { End = i; break; }else a[i] = b[pos], h[block[pos]] = min( h[block[pos]], a[i] );if( End ) {h[block[pos]] = 2e9, maxx[block[pos]] = 0;for( int i = End;i <= min( n, B * block[pos] );i ++ ) {h[block[pos]] = min( h[block[pos]], a[i] );maxx[block[pos]] = max( maxx[block[pos]], b[i] );}return;}End = 0;for( int i = block[pos] + 1;i <= block[n];i ++ )if( h[i] < b[pos] || b[pos] < maxx[i] ) { End = i; break; }else tag[i] = h[i] = b[pos];if( ! End ) return;if( tag[End] ) {for( int i = ( End - 1 ) * B + 1;i <= min( n, End * B );i ++ )a[i] = tag[End];tag[End] = 0;}for( int i = ( End - 1 ) * B + 1;i <= min( n, End * B );i ++ )if( a[i] < b[pos] || b[pos] < b[i] ) break;else a[i] = b[pos], h[End] = min( h[End], a[i] ); }int main() {scanf( "%d", &T );next :while( T -- ) {scanf( "%d", &n );B = sqrt( n );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );block[i] = ( i - 1 ) / B + 1;}for( int i = 1;i <= n;i ++ )scanf( "%d", &b[i] );for( int i = 1;i <= n;i ++ )if( a[i] < b[i] ) { printf( "-1\n" ); goto next; }for( int i = 1;i <= block[n];i ++ ) h[i] = 2e9, maxx[i] = tag[i] = 0;for( int i = 1;i <= n;i ++ ) {maxx[block[i]] = max( maxx[block[i]], b[i] );h[block[i]] = min( h[block[i]], a[i] );}int ans = 0;for( int i = 1;i <= n;i ++ )if( a[i] == b[i] || b[i] == tag[block[i]] ) continue;else modify( i ), ans ++;printf( "%d\n", ans );}return 0; }[HNOI2016]最小公倍數(shù)
source
solution
分塊。
答案為yes說明從uuu到vvv有一條路徑上的aaa的最大值和bbb的最大值恰好等于詢問給定的a,ba,ba,b
先將所有邊按aaa?從小到大排序,然后將所有詢問按bbb從小到大排序
將邊分塊,把所有詢問掛在 最大的 滿足小于等于詢問的aaa 的邊 所在的塊
- 具體而言就是枚舉塊iii,然后枚舉詢問,把aaa大于等于這個(gè)塊的塊頭的aaa,且小于下個(gè)塊塊頭的aaa的詢問拎出來
將這個(gè)塊前面的所有塊的邊重新按bbb排序
枚舉拎出來的詢問(因?yàn)樽铋_始的操作,所以按bbb??遞增)
將滿足bbb??小于等于詢問的bbb???的邊加入并查集合并(先前的操作保證aaa一定小于等于詢問的aaa)
然后暴力枚舉本塊中滿足的邊,并查集合并(判斷a,ba,ba,b都滿足才行)
更新枚舉的詢問的答案,要判斷a,ba,ba,b和最大值相等以外,還要保證兩點(diǎn)u,vu,vu,v連通(父親相同)
最后把暴力枚舉的邊,回退掉
所以是可撤銷并查集,不能路徑壓縮
塊的大小為nlog?m\sqrt{n\log m}nlogm?
code
#include <cmath> #include <cstdio> #include <algorithm> using namespace std; #define maxn 100005 struct node {int u, v, a, b, id;node(){}node( int U, int V, int A, int B, int ID = 0 ) {u = U, v = V, a = A, b = B, id = ID;} }g[maxn], E[maxn], Q[maxn], MS[maxn]; int n, m, q, top; int f[maxn], siz[maxn], maxA[maxn], maxB[maxn], ans[maxn];int find( int x ) {return x == f[x] ? x : find( f[x] ); }void merge( int u, int v, int a, int b ) {u = find( u ), v = find( v );if( siz[u] < siz[v] ) swap( u, v );MS[++ top] = node( u, v, maxA[u], maxB[u], siz[u] );if( u ^ v ) {f[v] = u;siz[u] += siz[v];maxA[u] = max( maxA[u], maxA[v] );maxB[u] = max( maxB[u], maxB[v] );}maxA[u] = max( maxA[u], a );maxB[u] = max( maxB[u], b ); }int main() {scanf( "%d %d", &n, &m );int block = sqrt( m * log2( n ) );for( int i = 1, u, v, a, b;i <= m;i ++ ) {scanf( "%d %d %d %d", &u, &v, &a, &b );E[i] = node( u, v, a, b );}sort( E + 1, E + m + 1, []( node x, node y ) { return x.a == y.a ? x.b < y.b : x.a < y.a; } );scanf( "%d", &q );for( int i = 1, u, v, a, b;i <= q;i ++ ) {scanf( "%d %d %d %d", &u, &v, &a, &b );Q[i] = node( u, v, a, b, i );}sort( Q + 1, Q + q + 1, []( node x, node y ) { return x.b == y.b ? x.a < y.a : x.b < y.b; } );for( int k = 1;k <= m;k += block ) {for( int i = 1;i <= n;i ++ )f[i] = i, siz[i] = 1, maxA[i] = maxB[i] = -1;int cnt = 0;for( int i = 1;i <= q;i ++ )if( E[k].a <= Q[i].a && ( k + block > m || Q[i].a < E[k + block].a ) )g[++ cnt] = Q[i];if( ! cnt ) continue;else sort( E + 1, E + k, []( node x, node y ) { return x.b == y.b ? x.a < y.a : x.b < y.b; } );for( int i = 1, j = 1;i <= cnt;i ++ ) {for( ;j < k && E[j].b <= g[i].b;j ++ )merge( E[j].u, E[j].v, E[j].a, E[j].b );top = 0;for( int w = k;w <= min( m, k + block - 1 );w ++ )if( E[w].a <= g[i].a && E[w].b <= g[i].b )merge( E[w].u, E[w].v, E[w].a, E[w].b );int u = find( g[i].u ), v = find( g[i].v );ans[g[i].id] = ( u == v && maxA[u] == g[i].a && maxB[u] == g[i].b );for( int w = top;w;w -- ) {u = MS[w].u;v = MS[w].v;f[v] = v;maxA[u] = MS[w].a;maxB[u] = MS[w].b;siz[u] = MS[w].id;}top = 0;}}for( int i = 1;i <= q;i ++ )if( ans[i] ) printf( "Yes\n" );else printf( "No\n" );return 0; }總結(jié)
以上是生活随笔為你收集整理的栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通用汽车旗下Cruise将召回950辆自
- 下一篇: 专题突破二之优先队列、st表——,Run