花花的森林forest

花花的森林forest

维护树的直径·并查集

题目大意:

花花有一棵带 n 个顶点的树 T,每个节点有一个点权 ai
有一天,他认为拥有两棵树更好一些。所以,他从 T 中删去了一条边。
第二天,他认为三棵树或许又更好一些。因此,他又从他拥有的某一棵树中去除了一条边。
如此往复。每一天,花花都会删去一条尚未被删去的边,直到他得到了一个包含了 n 棵只有一个点的树的森林。
定义一条简单路径1的权值为路径上点权之和,一棵树的直径为树上权值最大的简单路径。
花花认为树最重要的特征就是它的直径。所以他想请你算出任一时刻他拥有的所有树的直径
的乘积。因为这个数可能很大,他要求你输出乘积对 109+7 取模之后的结果。

题解:

本来是很简单的一道题,然而蒟蒻并没有想到这个:

设两棵树 T1T2 ,它们的直径的两个端点分别是 a1,b1a2,b2 ,当他们合并时,新的树的直径的两个端点也必定在这4个点中,只要枚举比较一下6种情况即可。

这个性质很重要!

http://blog.csdn.net/rzo_kqp_orz/article/details/52280811

简单证明一下。
我们看作是 x 所在的连通块通过边(x, y)连向 y 所在的连通块。
若新直径不经过(x, y),则就是原来的两条直径取 max。
若新直径经过(x, y),就要考虑 x 延伸到哪儿、y 延伸到哪儿了。由直径的定义可知,x 能走到的最远点之一是 x 所在连通块直径的端点,y 同理。因此这时新直径的两个端点都是旧直径的端点。
(这个证明也适用于增量法求树的直径,即我给一棵树加一个新点,那么新直径必有一端点是旧直径的端点)
(注意只能是树,普通图没有这些性质)

然后并查集维护,合并的时候检查一下6种情况即可。

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int N = 100005;
const int LOG = 21;

int n,w[N],edge[N][2],q[N],dis[N],fa[N][LOG],dep[N];
ll ans=1; int s[N],top;

ll pow(ll x,int k){
    ll res=1;
    while(k){
        if(k&1) res=res*x%mod;
        x=x*x%mod; k>>=1;
    }
    return res;
}
ll ni(ll x){ return pow(x,mod-2); }
void mul(ll &x,ll y){ x=x*y%mod; }
void div(ll &x,ll y){ x=x*ni(y)%mod; }

struct Edge{ int to,nxt; }e[N<<2]; int head[N],ec;
void add(int a,int b){ e[++ec].to=b; e[ec].nxt=head[a]; head[a]=ec; }

void dfs(int u,int f){
    dep[u]=dep[f]+1; fa[u][0]=f; dis[u]=dis[f]+w[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to; if(v==f)continue;
        dfs(v,u);
    }
}
void initlca(){
    for(int j=1;j<LOG;j++)
        for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}
int lca(int a,int b){
    if(dep[a]<dep[b])swap(a,b);
    int cha=dep[a]-dep[b];
    for(int j=LOG-1;j>=0;j--) 
        if((cha>>j)&1) a=fa[a][j];
    if(a!=b){
        for(int j=LOG-1;j>=0;j--) 
            if(fa[a][j]!=fa[b][j]) 
                a=fa[a][j],b=fa[b][j];
        a=fa[a][0];
    }
    return a;
}
int dist(int u,int v){ int f=lca(u,v); return dis[u]+dis[v]-dis[f]-dis[fa[f][0]]; }

void upd(int u,int v,int &res,int &x,int &y){
    int d=dist(u,v); if(d>res){ res=d; x=u,y=v; }
}
struct MergeSet{
    int pa[N],g[N][2],length[N];
    void init(){ for(int i=1;i<=n;i++) pa[i]=i, g[i][0]=g[i][1]=i, length[i]=w[i]; }
    int find(int x){ if(x!=pa[x])pa[x]=find(pa[x]); return pa[x]; }
    int merge(int a,int b){
        if(dep[a]>dep[b])swap(a,b);
        a=find(a); b=find(b);
        int x,y,res=0;
        upd(g[a][0],g[a][1],res,x,y);
        upd(g[a][0],g[b][0],res,x,y);
        upd(g[a][0],g[b][1],res,x,y);
        upd(g[a][1],g[b][0],res,x,y);
        upd(g[a][1],g[b][1],res,x,y);
        upd(g[b][0],g[b][1],res,x,y);
        g[a][0]=x; g[a][1]=y; length[a]=res; pa[b]=a;
        return res;
    }
    int len(int a){ a=find(a); return length[a]; }
} ms;


int main(){
    freopen("2.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",w+i);
    for(int i=1;i<n;i++){
        scanf("%d%d",edge[i],edge[i]+1);
        add(edge[i][0],edge[i][1]),add(edge[i][1],edge[i][0]);
    }
    for(int i=1;i<n;i++) scanf("%d",q+i);
    dfs(1,0); initlca(); ms.init(); 
    for(int i=1;i<=n;i++)mul(ans,w[i]); s[++top]=ans;
    for(int i=n-1;i>=1;i--){
        int u=edge[q[i]][0], v=edge[q[i]][1];
        if(dep[u]>dep[v])swap(u,v);
        div(ans,ms.len(u)); div(ans,ms.len(v));
        int res=ms.merge(u,v); mul(ans,res);
        s[++top]=ans;
    }
    while(top){ printf("%d\n",s[top--]); }
}
Python中的随机森林(Random Forest)是一种集成学习算法,它通过构建众多决策树并将它们的结果结合在一起来进行预测。在机器学习领域,特别是用于分类任务时,它可以有效地处理高维数据,并能够处理缺失值。例如,在鸢尾花(Iris)数据集上,随机森林可以用来识别三种不同类型的鸢尾花(Setosa、Versicolour和Virginica)。 鸢尾花数据集是一个经典的示例,通常用于初学者入门机器学习。在Python中,我们可以使用scikit-learn库中的`sklearn.ensemble.RandomForestClassifier`来创建随机森林模型。首先,你需要加载数据(如iris.loaders.load_iris()),然后对特征进行预处理,接着划分训练集和测试集,最后使用`fit()`方法训练模型,`predict()`方法做预测,评估性能通常会用到交叉验证和accuracy_score等函数。 下面是一个简单的例子: ```python from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score # 加载鸢尾花数据集 iris = load_iris() X = iris.data y = iris.target # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 创建并训练随机森林模型 rf = RandomForestClassifier(n_estimators=100, random_state=42) rf.fit(X_train, y_train) # 预测 y_pred = rf.predict(X_test) # 计算准确率 accuracy = accuracy_score(y_test, y_pred) print("Accuracy:", accuracy) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值