zoukankan      html  css  js  c++  java
  • 1977: [BeiJing2010组队]次小生成树 Tree

    题解:和cf的一道题比较类似 首先跑一个MST 对于这个树做树链剖分 枚举不在这个树上的边找严格小于这条边的最大边权值 然后求ans

    #include <bits/stdc++.h>
    #define ll long long
    const int MAXN=1e5+10;
    const int maxn=3e5+10;
    const int inf=1e9+20;
    using namespace std;
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    vector<pair<int,int> >vec[MAXN];
    typedef struct Edge{
        int u,v,vul;bool flag;
        friend bool operator<(Edge aa,Edge bb){return aa.vul<bb.vul;}
    }Edge;
    Edge edge[maxn];
    int n,m,f[MAXN];
    int find1(int x){
        if(f[x]==x)return x;
        else return f[x]=find1(f[x]);
    }
    int key[MAXN],fa[MAXN],dep[MAXN],num[MAXN],son[MAXN];
    void dfs(int v,int pre,int deep){
        dep[v]=deep+1;num[v]=1;fa[v]=pre;
        for(int i=0;i<vec[v].size();i++){
    	int u=vec[v][i].first;
    	if(u!=pre){
    	    key[u]=vec[v][i].second;
    	    dfs(u,v,deep+1);
    	    num[v]+=num[u];
    	    if(son[v]==-1||num[son[v]]<num[u])son[v]=u;
    	}
        }
    }
    int tp[MAXN],cnt,p[MAXN],fp[MAXN];
    void dfs1(int v,int td){
        p[v]=++cnt;fp[p[v]]=v;tp[v]=td;
        if(son[v]!=-1)dfs1(son[v],td);
        for(int i=0;i<vec[v].size();i++){
    	if(vec[v][i].first!=fa[v]&&vec[v][i].first!=son[v])dfs1(vec[v][i].first,vec[v][i].first);
        }
    }
    int maxx[MAXN<<2],maxx1[MAXN<<2];
    void up(int x){
        maxx[x]=max(maxx[x<<1],maxx[x<<1|1]);
        maxx1[x]=maxx1[x<<1];
        if(maxx[x<<1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx[x<<1]);
        if(maxx[x<<1|1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx[x<<1|1]);
        if(maxx1[x<<1|1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx1[x<<1|1]);
    }
    void built(int rt,int l,int r){
        if(l==r){maxx[rt]=key[fp[l]];maxx1[rt]=-1;return ;}
        int mid=(l+r)>>1;
        built(rt<<1,l,mid);
        built(rt<<1|1,mid+1,r);
        up(rt);
    }
    int ans1;
    void querty(int rt,int l,int r,int ql,int qr,int vul){
        if(ql<=l&&r<=qr){
    	if(maxx[rt]==vul)ans1=max(ans1,maxx1[rt]);
    	else ans1=max(ans1,maxx[rt]);
    	return ;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)querty(rt<<1,l,mid,ql,qr,vul);
        if(qr>mid)querty(rt<<1|1,mid+1,r,ql,qr,vul);
    }
    int slove(int u,int v,int t){
        int uu=tp[u];int vv=tp[v];
        ans1=-1*inf;
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
    	querty(1,1,n,p[uu],p[u],t);
    	u=fa[uu];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        if(u!=v)querty(1,1,n,p[son[u]],p[v],t);
        return ans1;
    }
    int main(){
        n=read();m=read();int u,v,vul;
        for(int i=1;i<=m;i++)edge[i].u=read(),edge[i].v=read(),edge[i].vul=read();
        for(int i=1;i<=n;i++)f[i]=i,son[i]=-1;
        sort(edge+1,edge+m+1);ll ans=0;
        for(int i=1;i<=m;i++){
    	int t1=find1(edge[i].u);
    	int t2=find1(edge[i].v);
    	if(t1==t2)continue;
    	ans+=edge[i].vul;
    	f[t1]=t2;vec[edge[i].u].push_back(make_pair(edge[i].v,edge[i].vul));
    	vec[edge[i].v].push_back(make_pair(edge[i].u,edge[i].vul));edge[i].flag=1;
        }
        //cout<<ans<<endl;
        dfs(1,0,0);dfs1(1,1);built(1,1,n);
       // cout<<"sb"<<endl;
        ll ans2=1e18;
        for(int i=1;i<=m;i++){
    	if(edge[i].flag)continue;
    	vul=slove(edge[i].u,edge[i].v,edge[i].vul);
    	if(vul<0)continue;
    	ans2=min(ans2,ans-vul+1ll*edge[i].vul);
        }
        printf("%lld
    ",ans2);
        return 0;
    }
    

    1977: [BeiJing2010组队]次小生成树 Tree

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 3853  Solved: 1104
    [Submit][Status][Discuss]

    Description

    小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    Input

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

    Output

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    Sample Input

    5 6
    1 2 1
    1 3 2
    2 4 3
    3 5 4
    3 4 3
    4 5 6

    Sample Output

    11

    HINT

    数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

  • 相关阅读:
    1)①爬取中国新闻网科技相关部分新闻
    摘记
    KNN算法[分类算法]
    Naive Bayes(朴素贝叶斯算法)[分类算法]
    Oracle 隔离级别
    解决问题没必要过于纠结于原理
    Oracle DBMS_METADATA.GET_DDL
    【听海日志】之ORACLE物化视图 [转]http://www.itpub.net/thread-1614812-1-1.html
    oracle 12c 基础
    Postgres查看数据库中的表及表中字段和类型
  • 原文地址:https://www.cnblogs.com/wang9897/p/9343678.html
Copyright © 2011-2022 走看看