CF1218A
虚高 *2800。放模拟赛 T2 人均切了。
先想树的情况怎么做。枚举每个起点,剩下的贡献就是定值。求这个值可以钦定
然后放到基环树上,发现需要注意环的情况,在一个环上先往一个方向走和另一个方向的贡献是不一样的。发现可以通过一个环上的区间 dp 解决。
对于环上一个点
设环上点编号为
初始值
发现空间会炸,于是滚动一下。能过。
code:
点击查看代码
int n,m;
int tot,head[N];
struct node{int to,nxt;}e[N<<1];
il void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
namespace s1{
int siz[N],fa[N];
void dfs1(int u,int f){
siz[u]=1,fa[u]=f;
go(i,u){
int v=e[i].to;
if(v==f)continue;
dfs1(v,u),siz[u]+=siz[v];
}
}
void solve(){
dfs1(1,0);
int sum=0;
rep(i,1,n)sum+=siz[i];
int ans=0;
rep(i,1,n){
int x=sum,u=i;
while(u!=1)x+=n-2*siz[u],u=fa[u];
ans=max(ans,x);
}
printf("%d\n",ans);
}
}
namespace s2{
int k,cyc,siz[N],dep[N],fa[N],dp[N][2],id[N];
bool vis[N],inc[N];
vector<int> g;
void dfs1(int u,int f){
vis[u]=1,dep[u]=dep[f]+1,fa[u]=f;
go(i,u){
int v=e[i].to;
if(vis[v]){
if(v!=f)cyc=(i+1)/2;
continue;
}
dfs1(v,u);
}
}
void find_cyc(int u,int v){
vector<int> h;
if(dep[u]<dep[v])swap(u,v);
while(dep[u]>dep[v])g.eb(u),u=fa[u];
while(u!=v)g.eb(u),h.eb(v),u=fa[u],v=fa[v];
g.eb(u);
while(h.size())g.eb(h.back()),h.pop_back();
}
void dfs2(int u,int f){
siz[u]=1,fa[u]=f;
go(i,u){
int v=e[i].to;
if(v==f||inc[v])continue;
dfs2(v,u),siz[u]+=siz[v];
}
}
void solve(){
dfs1(1,0),find_cyc(e[cyc*2-1].to,e[cyc*2].to);
for(int i=0;i<(int)g.size();i++)inc[g[i]]=1,id[g[i]]=i;
for(int i:g)dfs2(i,0);
k=g.size();int sum=0;
rep(i,1,n)sum+=siz[i];
rep(i,1,n){
int x=sum,u=i;
while(!inc[u])x+=n-2*siz[u],u=fa[u];
dp[id[u]][1]=max(dp[id[u]][1],x+n-siz[u]);
}
rep(len,2,k){
int p=len&1;
rep(i,0,k-1)dp[i][p]=0;
rep(i,0,k-1){
int j=(i+len-1)%k;
dp[i][p]=max(dp[i][p^1]+siz[g[j]]*(len-2),dp[(i+1)%k][p^1]+siz[g[i]]*(len-2));
}
}
int ans=0;
rep(i,0,k-1)ans=max(ans,dp[i][k&1]);
printf("%d\n",ans);
}
}
void Yorushika(){
scanf("%d",&n);
rep(i,1,n){
int u=read()+1,v=read()+1;
add(u,v),add(v,u);
}
s2::solve();
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}