1007& Rikka with Travels Rikka with Travels

文章目录

Rikka with Travels

换根dp



#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define  FI first
#define  SE second
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl; 
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
LL qpow(LL a,LL b){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> P;
const int maxn = 1e5+10;
int depth[maxn],dp[maxn];
int depth2[maxn],dp2[maxn];
int num[maxn];
vector<int> G[maxn];
void dfs1(int u,int fa){
	depth[u] = dp[u] =1;
	vector<int> v(2,0);
	for(auto c: G[u]){
		if(c == fa) continue;
		dfs1(c,u);
		depth[u] =max(depth[u],depth[c]+1);
		dp[u] = max(dp[u],dp[c]);
		v.push_back(depth[c]);
	}
	sort(v.begin(),v.end(),greater<int>());
	dp[u] = max(dp[u],v[0]+v[1]+1);
}
void update(int a,int b){

	if(a < b) swap(a,b);
	num[a] = max(num[a],b);
}
void dfs2(int u,int fa){
	P p(0,0);
   vector<P> v1(2,p),v2(2,p);
   v1.Pb(P(dp2[u],u));
   v2.Pb(P(depth2[u]-1,u));
   for(auto c:G[u]){
   		if(c == fa) continue;
   		v1.Pb(P(dp[c],c));
   		v2.Pb(P(depth[c],c));
   }
   // cout<<"Sor"<<endl;
   sort(v1.begin(),v1.end(),greater<P>());
   sort(v2.begin(),v2.end(),greater<P>());
   for(auto c:G[u]){
   		if(c == fa) continue;
   		// 求最长链
   		// cout<<c<<endl;
   		int &M = dp2[c];
   		// cout
   		M = depth2[c] = 0;
   		// cout<<""
   		int cnt = 0;
   		for(int i = 0;i < 3&&cnt<2; ++i){
   			if(v2[i].second == c)continue;
   			++cnt;
   			M += v2[i].first;
   			depth2[c] = max(depth2[c],v2[i].first+2);
   		}
   		M++;
   		int t =0;
   		if(v1[t].second==c)++t;
   		M = max(M,v1[t].first);
   		update(M,dp[c]);
   		dfs2(c,u);
   }

}
int main(void)
{
   int T;cin>>T;
   while(T--){
   		int n;cin>>n;
   		for(int i = 1;i <=n; ++i)
   			G[i].clear(),num[i] = 0;
   		for(int i = 1;i < n;++i){
   			int u,v;scanf("%d%d",&u,&v);
   			G[u].Pb(v);
   			G[v].Pb(u);
   		}
   		// cout<<"DF"<<endl;
   		dfs1(1,-1);
   		// cout<<dp[1]<<" "<<depth[1]<<endl;
   		dp2[1] = 1,depth2[1] = 1;
   		// cout<<"dfs1 end"<<endl;
   		dfs2(1,-1);
   		// DEBUG;
   		LL ans= 0;
   		LL t=0;
   		num[n+1] = 0;
   		for(int i = n;i >= 1; --i){
   			num[i] = max(num[i],num[i+1]);
   			ans += min(num[i],i);
   			if(num[i] >= i)
   				t++;
   			// cout<<i<<" "<<num[i]<<endl;
   		}

   		cout<<ans*2-t<<endl;
   }

   return 0;
}


//
/*


dfs1 高度,最长链

dfs2 除这个子树外的最长链

dp[son],depth[son]+depth[son]
2
5
1 2
2 3
3 4
3 5
*/ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值