CF372D. Choosing Subtree is Fun
生活随笔
收集整理的這篇文章主要介紹了
CF372D. Choosing Subtree is Fun
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
CF372D. Choosing Subtree is Fun
Solution
想了一晚都不會(huì),一覺(jué)醒來(lái)就悟了QwQQwQQwQ
之前一直想著如何用類似樹(shù)形DPDPDP的方法求出每一個(gè)點(diǎn)的貢獻(xiàn)再合并,然后突然發(fā)現(xiàn)直接枚舉區(qū)間就行了。
考慮區(qū)間確定時(shí),其實(shí)就是求區(qū)間內(nèi)節(jié)點(diǎn)在原樹(shù)上的斯坦納樹(shù)的點(diǎn)數(shù)。
我們枚舉左端點(diǎn)lll,顯然隨著lll的增加,rrr時(shí)非降的,因此動(dòng)態(tài)維護(hù)斯坦納樹(shù)的點(diǎn)數(shù)即可。
因?yàn)樗固辜{樹(shù)的邊數(shù),就是每個(gè)關(guān)鍵點(diǎn)的深度和減去dfsdfsdfs序相鄰的關(guān)鍵點(diǎn)的LCALCALCA的深度和,而點(diǎn)數(shù)為邊數(shù)加一。每次操作會(huì)加入一個(gè)點(diǎn),刪除一個(gè)點(diǎn),用setsetset維護(hù)關(guān)鍵點(diǎn)的dfsdfsdfs序,計(jì)算貢獻(xiàn)即可。
Code
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <cassert> #include <string.h> //#include <unordered_set> //#include <unordered_map> //#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B) #define PB(A) push_back(A) #define SIZE(A) ((int)A.size()) #define LEN(A) ((int)A.length()) #define FOR(i,a,b) for(int i=(a);i<(b);++i) #define fi first #define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; } template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll; typedef unsigned long long ull; typedef long double lod; typedef pair<int,int> PR; typedef vector<int> VI;const lod eps=1e-11; const lod pi=acos(-1); const int oo=1<<30; const ll loo=1ll<<62; const int mods=1e9+7; const int MAXN=400005; const int INF=0x3f3f3f3f;//1061109567 /*--------------------------------------------------------------------*/ inline int read() {int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } set<int> Set; vector<int> e[MAXN]; int id[MAXN],dfn[MAXN],DFN=0,dep[MAXN],mn[18][MAXN],n,Log[MAXN],sum=0,k,ans=1,num=0,eul[MAXN],ID[MAXN]; void dfs(int x,int father) {id[dfn[x]=++DFN]=x,dep[x]=dep[father]+1,ID[eul[x]=++num]=x;for (auto v:e[x])if (v!=father) {dfs(v,x);ID[++num]=x;} } void Init() {for (int i=1;i<=num;i++) mn[0][i]=dep[ID[i]];for (int i=1;i<=17;i++)for (int j=1;j<=num-(1<<i)+1;j++) mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]); } int getdep(int l,int r) {l=eul[id[l]],r=eul[id[r]];if (l>r) swap(l,r);int x=Log[r-l+1];return min(mn[x][l],mn[x][r-(1<<x)+1]); } void add(int x) {set<int>::iterator it=Set.lower_bound(x);int nxt,lst;if (it==Set.end()) nxt=*Set.begin(),it--,lst=*it;else if (it==Set.begin()) nxt=*it,lst=*Set.rbegin();else nxt=*it,it--,lst=*it;if (nxt==lst) sum+=getdep(lst,lst)+getdep(x,x)-getdep(x,lst)*2;else sum+=getdep(x,x)+getdep(lst,nxt)-getdep(x,nxt)-getdep(lst,x);Set.insert(x); } void del(int x) {Set.erase(Set.find(x));if (!Set.size()) return; set<int>::iterator it=Set.lower_bound(x);int nxt,lst;if (it==Set.end()) nxt=*Set.begin(),it--,lst=*it;else if (it==Set.begin()) nxt=*it,lst=*Set.rbegin();else nxt=*it,it--,lst=*it;if (nxt==lst) sum-=getdep(lst,lst)+getdep(x,x)-getdep(x,lst)*2;else sum-=getdep(x,x)+getdep(lst,nxt)-getdep(x,nxt)-getdep(lst,x); } signed main() {n=read(),k=read(),ans=1;for (int i=1,u,v;i<n;i++) u=read(),v=read(),e[u].PB(v),e[v].PB(u);Log[1]=0; for (int i=2;i<=n*2;i++) Log[i]=Log[i>>1]+1;dfs(1,0),Init(),Set.insert(dfn[1]);for (int l=1,r=1;l<n;l++){while (r<n&&sum+1<=k) r++,add(dfn[r]);if (sum+1>k) upmax(ans,r-l);else upmax(ans,r-l+1);del(dfn[l]);}printf("%d\n",ans);return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的CF372D. Choosing Subtree is Fun的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 市场调研-全球与中国软磁粉芯市场现状及未
- 下一篇: CF653F. Paper task