日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数

發(fā)布時(shí)間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 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說明從uuuvvv有一條路徑上的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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。