题意:就是给你一棵联通的树,一共n个节点,每个节点的编号也代表该节点的海拔,现在需要你在这颗树上找到一个起点,一个终点,满足先上升后下降的性质,起点或终点不同即为不同的路径,问满足条件的路径条数由多少条。
思路:直观的考虑就是先求每个节点单减得路径由多少条,每条的长度,这样再推一下各个路径之间和最后贡献之间的关系,就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll=long long ;
const int maxn=2*100000+10;
ll dp[maxn],dpp[maxn],ans;
vector<int>N[maxn];
void dfs(int r,int f,int x)
{
for(auto it=N[r].begin(); it!=N[r].end(); it++)
{
if(*it==f)
continue;
if(*it>r)
{
if(x==2)
{
dp[*it]+=dp[r];
dpp[*it]+=dpp[r];
// ans+=dp[r];
}
// if(x==3)
// {
// ans+=dp[*it]*(dpp[r]-dp[*it]-1);
printf("%lld %lld %d\n",ans,dp[r],r);
// dpp[r]-=dp[*it];
// }
}
dfs(*it,r,x);
if(*it<r)
{
if(x==1)
{
dp[r]+=dp[*it];
dpp[r]+=dpp[*it];
// ans+=dp[*it];
}
else if(x==3)
{
ans+=dp[*it]*(dpp[r]-dp[*it]-1);
// printf("%lld %lld %d\n",ans,dp[r],r);
dpp[r]-=dp[*it];
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
// ans=0;
scanf("%d",&n);
memset(dp,0,sizeof(dp));
memset(dpp,0,sizeof(dpp));
for(int i=1; i<maxn; i++)
N[i].clear();
for(int i=0; i<n-1; i++)
{
dp[i]=1;
dpp[i]=1;
int x,y;
scanf("%d%d",&x,&y);
N[x].push_back(y);
N[y].push_back(x);
}
dp[n-1]=1;
dp[n]=1;
dpp[n-1]=1;
dpp[n]=1;
ans=0;
dfs(n,-1,1);
dfs(n,-1,2);
dfs(n,-1,3);
printf("%lld\n",ans*2);
}
}
/*
21
4
1 4
2 4
3 4
*/