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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

CF1654-G. Snowy Mountain(2900) GOOD

發布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1654-G. Snowy Mountain(2900) GOOD 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

思路

分析最優解性質

  • 任意兩個點高度至多相差1
  • 任取一條最優滑雪路徑。最后反復出現的點一定最多僅有2個。其余的路徑上的點互不相同
    • 若不然,可以將其余的重復點構成的路徑加到這兩個點的反復中。
  • 如果能反復,考慮在點uuu開始進行反復。開始點為點v。則最長能滑動的總路徑為2hv?hu2h_v - h_u2hv??hu?這是因為從點v到點u多余能量hv?huh_v - h_uhv??hu?,在u點開始與其鄰居進行反復,直到能量消耗為0.至此,共消耗能量2(hv?hu)2 (h _v - h_u)2(hv??hu?)。加上從u點到doge能滑動最長的距離huh_uhu?
  • 由上式可見,若huh_uhu?較小,則滑動的距離較大。因此對每個結點找其能到達的高度最低的u點,如果能找到答案為上述式子,否則答案為自身的高度

逆向考察

  • 對上述u點,其必須滿足至少有一個鄰居與其有同樣的高度。對于這樣的點對u,vu,vu,v,v是u的與其相同高度的鄰居。其到達它們最近的doge的路徑互不相交。因此∑u∈Shu\sum_{u \in S} h_uuS?hu?較小。可以證明其是O(n)O(n)O(n)級別的。于是不同的huh_uhu?個數是n\sqrt{n}n?級別的。
  • 對每種可能的高度對應的結點考察其能夠到達的所有結點。

實現(官方)

  • 先使用多源bfs求出所有點的高度。
while(!q.empty()){int x=q.front();q.pop();for(auto c:adj[x]){if(d[c] == -1){d[c]=d[x]+1;q.push(c);}}}
  • 利用h數組記錄可行的高度i是幾號高度,利用g數組記錄z號高度的實際高度。
for(int i=1; i<=n ;i++){f[d[i]].push_back(i);for(auto c:adj[i]){if(d[c]==d[i] && c>i){use[d[i]]=true;}}}for(int i=0; i<=n ;i++){if(use[i]){g[++z]=i;h[i]=z;}}/*
  • ans[i][z]表示i號結點到達z號高度滿足鄰居有相同z號高度的結點所需要的最少初始能量,其中z的取值是n\sqrt{n}n?級別的。
  • 將結點按高度進行分層。假設下一層所需要到達的每一種可能高度的最低能量已經求出,下一層對上一層按照公式:
    ans[x][i]=min(ans[x][i],max(0,ans[c][i]?1))ans[x][i]=min(ans[x][i],max(0,ans[c][i]-1))ans[x][i]=min(ans[x][i],max(0,ans[c][i]?1))
    其中c是下一層結點,x是當前層結點。
for(auto c:adj[x]){if(d[c]==d[x]-1){for(int i=1; i<=z ;i++) ans[x][i]=min(ans[x][i],max((ll)0,ans[c][i]-1));}}
  • 同層結點的轉移,利用up and down dp,通過兩次dfs(待學習)
    ans[c][i]=min(ans[c][i],ans[id][i]+1)ans[c][i]=min(ans[c][i],ans[id][i]+1)ans[c][i]=min(ans[c][i],ans[id][i]+1)
    其中id是c的鄰居,對每種高度i循環執行
void dfs(int id,int p){vis[id]=true;for(auto c:adj[id]){if(c==p || d[c]!=d[id]) continue;dfs(c,id);for(int i=1; i<=z ;i++){ans[id][i]=min(ans[id][i],ans[c][i]+1);}ans[id][h[d[id]]]=0;}}void dfs2(int id,int p){for(auto c:adj[id]){if(c==p || d[c]!=d[id]) continue;for(int i=1; i<=z ;i++){ans[c][i]=min(ans[c][i],ans[id][i]+1);}ans[c][h[d[c]]]=0;dfs2(c,id);}} #include<bits/stdc++.h>using namespace std;typedef long long ll;#define fi first#define se second#define int long longconst ll mod=998244353;const int N=2e5+1;int n;int d[N];queue<int>q;vector<int>adj[N];int g[N],h[N],z;bool use[N];vector<int>ans[N];vector<int>f[N];bool vis[N];void dfs(int id,int p){vis[id]=true;for(auto c:adj[id]){if(c==p || d[c]!=d[id]) continue;dfs(c,id);for(int i=1; i<=z ;i++){ans[id][i]=min(ans[id][i],ans[c][i]+1);}ans[id][h[d[id]]]=0;}}void dfs2(int id,int p){for(auto c:adj[id]){if(c==p || d[c]!=d[id]) continue;for(int i=1; i<=z ;i++){ans[c][i]=min(ans[c][i],ans[id][i]+1);}ans[c][h[d[c]]]=0;dfs2(c,id);}}main(){ios::sync_with_stdio(false);cin.tie(0);cin >> n;for(int i=1; i<=n ;i++){int x;cin >> x;if(x==1) {q.push(i);d[i] = 0;}else d[i]=-1; }for(int i=1; i<n ;i++){int u,v;cin >> u >> v;adj[u].push_back(v);adj[v].push_back(u);}while(!q.empty()){int x=q.front();q.pop();for(auto c:adj[x]){if(d[c] == -1){d[c]=d[x]+1;q.push(c);}}}for(int i=1; i<=n ;i++){f[d[i]].push_back(i);for(auto c:adj[i]){if(d[c]==d[i] && c>i){use[d[i]]=true;}}}for(int i=0; i<=n ;i++){if(use[i]){g[++z]=i;h[i]=z;}}/*for(int i=1; i<=n ;i++){cout << d[i] << ' ';}cout << endl;*/for(int i=1; i<=n ;i++){ans[i].resize(z+1);}for(int j=0; j<=n ;j++){for(auto x:f[j]){for(int i=1; i<=z ;i++) ans[x][i]=1e9;for(auto c:adj[x]){if(d[c]==d[x]-1){for(int i=1; i<=z ;i++) ans[x][i]=min(ans[x][i],max((ll)0,ans[c][i]-1));}}}for(auto x:f[j]){if(!vis[x]){dfs(x,0);dfs2(x,0);}}/*for(auto x:f[j]){cout << x << ": ";for(int i=1; i<=z ;i++) cout << ans[x][i] << ' ';cout << '\n';}*/}for(int i=1; i<=n ;i++){int res=d[i];for(int j=1; j<=z ;j++){if(ans[i][j]==0) res=max(res,d[i]*2-g[j]);}cout << res << ' ';}cout << '\n';}

總結

以上是生活随笔為你收集整理的CF1654-G. Snowy Mountain(2900) GOOD的全部內容,希望文章能夠幫你解決所遇到的問題。

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