zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans*2);
    	return 0;
    }
    
  • 相关阅读:
    LR 场景设置
    win7 快捷键
    P1903 [国家集训队]数颜色 / 维护队列(莫队区间询问+单点修改)
    A
    P1494 [国家集训队]小Z的袜子(莫队)
    P2709 小B的询问(莫队入门)
    G
    #6285. 数列分块入门 9(区间的最小众数 离散化+数列分块)
    #6284. 数列分块入门 8(区间询问等于一个数 cc 的元素,并将这个区间的所有元素改为 c)
    #6283. 数列分块入门 7(区间乘法,区间加法,单点询问)
  • 原文地址:https://www.cnblogs.com/sz-wcc/p/12796475.html
Copyright © 2011-2022 走看看