51Nod3105 小明喜欢树 V2

Problem

小明非常喜欢树,有一天小明得到这样一棵树,每个树节点都有一个编号,有n个节点的树的编号为1到n,每个编号代表该节点的海拔高度,现在小明要在这颗树上找到一些路径,从起点到终点需要满足海拔先单调上升后单调下降的性质,起点或终点不同即为不同的路径,问满足条件的路径有多少条,聪明的你可以帮助小明解决这个问题吗?

Solution

计算一个点周围小于等于它的点,包括它自身。然后对于每一个点,连通的小于它的点,之前算出来的值(可以认为这个值是这条分支的起点/终点数)两两相乘。

code1只是简单记忆化了一下,code2融合进计算值里,由于每次只是和前面的sum,不是和总sum相乘,所以答案要*2.

Code1

#include<stdio.h>
using namespace std;
#define db double
#define ll long long
inline int rd(){
	int x=0;
	char ch=0;
	while(ch<'0'||ch>'9') {ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
const int MAXN=1000020;
int n;
int g[MAXN];
struct E{
	int u,v,nex;
}e[MAXN*2];
ll f[MAXN];
ll dfs(int u){
	ll sum=0;
	for(int i=g[u];i>0;i=e[i].nex){
		int v=e[i].v;
		if(v<u) sum+=f[v]==0?dfs(v):f[v];
	}
	return f[u]=sum+1;
}
ll ans=0;
int main(){
	//io_opt;
	n=rd();
	int x,y;
	for(int i=1;i<n;i++){
		x=rd();
		y=rd();
		e[i]=(E){x,y,g[x]};g[x]=i;
		e[i+n-1]=(E){y,x,g[y]};g[y]=i+n-1;
	}
	for(int i=n;i>=1;i--){
		if(!f[i]) dfs(i);
	}
	for(int i=1;i<=n;i++){
		ll sum=0;
		for(int j=g[i];j>0;j=e[j].nex){
			int v=e[j].v;
			if(v<i) sum+=f[v];
		}
		for(int j=g[i];j>0;j=e[j].nex){
			int v=e[j].v;
			if(v<i) ans+=f[v]*(sum-f[v]);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

code2

#include<stdio.h>
using namespace std;
#define db double
#define ll long long
const int MAXN=1000020;
int n;
int g[MAXN];
struct E{
	int u,v,nex;
}e[MAXN*2];
int f[MAXN];
int sum[MAXN];
ll ans=0;
int dfs(int u){
	for(int i=g[u];i>0;i=e[i].nex){
		int v=e[i].v;
		if(v<u){
			sum[u]+=f[v]==0?dfs(v):f[v];
			ans+=f[v]*(ll)(sum[u]-f[v]);
		}
	}
	return f[u]=sum[u]+1;
}
int main(){
	//io_opt;
	scanf("%d",&n);
	int x,y;
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		e[i]=(E){x,y,g[x]};g[x]=i;
		e[i+n-1]=(E){y,x,g[y]};g[y]=i+n-1;
	}
	for(int i=n;i>=1;i--){
		if(!f[i]) dfs(i);
	}
	printf("%lld\n",ans*2);
	return 0;
}
posted @ 2020-04-28 19:03  CCWUCMCTS  阅读(292)  评论(0编辑  收藏  举报