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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CodeForces 1610H Squid Game(延迟贪心 + 构造 + 树状数组)

發布時間:2023/12/3 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CodeForces 1610H Squid Game(延迟贪心 + 构造 + 树状数组) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

洛谷鏈接

solution

考慮重新隨便欽定一個點為“根”,并且強制根必須是關鍵點。

則所有 x?yx-yx?y 不是直系祖先-子代的要求(要求Ⅰ),即 xxx 不是 yyy 祖先,yyy 也不是 xxx 祖先,一定都被滿足。

所有 x?yx-yx?y 是直系祖先-子代的要求(要求Ⅱ)都不能被滿足。根離這條路徑最近的點一定是 x/yx/yx/y 中某個端點。

下面不妨仍認為 111 為根。考慮怎么才能最少且滿足所有的要求Ⅱ。

采用延遲貪心的思想。從下往上考慮盡量晚放關鍵點(最淺化關鍵點的深度)

感性想想這確實是最優的

到這里都是基于根被選為關鍵點的后續操作,但是這個根一定要成為關鍵點嗎?

也有可能存在,考慮要求Ⅱ的時候,晚放的某些關鍵點恰好把所有的要求Ⅰ也順帶解決了的情況。

所以延遲貪心后,又反過來考慮是否要新增一個根為關鍵點,增加 111 的貢獻。

換言之,在強制根的想法上找到了解法發現可行,現在回來再考慮假設的必要性。

發現,如果為了解決要求Ⅱ而放置的關鍵點無法解決要求Ⅰ,則要求Ⅰ的 lca\text{lca}lca 一定深度更小 / 這個關鍵點一定在要求Ⅰ的某個端點子樹內。

只要有一個要求Ⅰ無法被滿足,都意味著這個根作為關鍵點是必需的。

dfs 樹,利用 dfndfndfn 序,用樹狀數組維護關鍵點的信息即可。

注意:雖然之前說隨便找個點做根,但這只是一種思考方式,并不是真的在代碼中進行換根操作。

code

#include <bits/stdc++.h> using namespace std; #define maxn 300005 vector < pair < int, int > > MS; vector < int > G[maxn], E[maxn]; int n, m, cnt; int dep[maxn], L[maxn], R[maxn], t[maxn], id[maxn]; int f[maxn][20];void dfs( int u ) {for( int i = 1;i < 20;i ++ ) f[u][i] = f[f[u][i - 1]][i - 1];L[u] = ++ cnt;for( int v : G[u] ) {dep[v] = dep[u] + 1;dfs( v );}R[u] = cnt; }int lca( int x, int d ) { for( int i = 19;~ i;i -- ) if( d >> i & 1 ) x = f[x][i]; return x; }void Add( int i ) { for( ;i <= n;i += i & -i ) t[i] ++; }int Ask( int i ) { int ans = 0; for( ;i;i -= i & -i ) ans += t[i]; return ans; }int get( int x ) { return Ask( R[x] ) - Ask( L[x] - 1 ); }int main() {scanf( "%d %d", &n, &m );for( int i = 2;i <= n;i ++ ) {scanf( "%d", &f[i][0] );G[f[i][0]].push_back( i );}dfs( 1 );for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );if( dep[u] > dep[v] ) swap( u, v );if( f[v][0] == u ) return ! printf( "-1\n" );E[u].push_back( v );}iota( id + 1, id + n + 1, 1 );sort( id + 1, id + n + 1, []( int x, int y ) { return dep[x] > dep[y]; } );int ans = 0;for( int i = 1;i <= n;i ++ ) {int x = id[i];for( int y : E[x] ) {if( dep[x] == dep[y] ) MS.push_back( { x, y } ); //兩個深度一樣則一定隸屬于不同子樹else {int z = lca( y, dep[y] - dep[x] - 1 ); //爬到深度比x深1的祖先點if( f[z][0] ^ x ) MS.push_back( { x, y } ); //證明x,y不屬于同一個子樹else {if( get( z ) - get( y ) ) continue; //祖先-子代關系 判斷x-y這條鏈(除了x,y)有沒有關鍵點存在else ans ++, Add( L[z] );//新增關鍵點}}}}for( int i = 0;i < MS.size();i ++ ) {int x = MS[i].first, y = MS[i].second;if( get( x ) + get( y ) == ans ) { ans ++; break; } //判斷x,y子樹包含了所有的關鍵點,那么這個x-y旁系祖先-子代關系就必須通過根來滿足了}printf( "%d\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的CodeForces 1610H Squid Game(延迟贪心 + 构造 + 树状数组)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。