CF1218A

虚高 *2800。放模拟赛 T2 人均切了。

先想树的情况怎么做。枚举每个起点,剩下的贡献就是定值。求这个值可以钦定 11 为根求出所有的 sizsiz,然后枚举 ii 为起点,以 ii 为起点的答案就是 sizi\sum siz_i 加上 ii11 路径上,不含 11 的所有点的 jn2×sizj\sum_j n-2\times siz_j

然后放到基环树上,发现需要注意环的情况,在一个环上先往一个方向走和另一个方向的贡献是不一样的。发现可以通过一个环上的区间 dp 解决。

对于环上一个点 ii 的贡献,我们只考虑一个在环上,且不在起点所对应环上的点且不为 ii 的点 jj,当染黑 jj 时,ii 造成的贡献。

设环上点编号为 0,1,,k10,1,\cdots ,k-1,对应点分别为 a0,a1,,ak1a_0,a_1,\cdots,a_{k-1},dpi,jdp_{i,j} 为环上编号为 ii 的点开始的一段长为 jj 的区间的最大贡献,则有 dpi,j=max(dpi,j1+(j2)×sizai+j1,dp(i+1)modk,j1+(j2)×sizai)dp_{i,j}=\max(dp_{i,j-1}+(j-2)\times siz_{a_{i+j-1}},dp_{(i+1)\bmod k,j-1}+(j-2)\times siz_{a_i})。其中 sizsiz 是将在环上的点视为根的 sizsiz

初始值 dpi,1dp_{i,1} 可以根据上面计算树的方法,得到以 ii 为根的子树内每个点为起点的答案,再取 max\max

发现空间会炸,于是滚动一下。能过。O(n2)O(n^2)

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();
}