zoukankan      html  css  js  c++  java
  • 【2020.11.30提高组模拟】删边(delete) 题解

    【2020.11.30提高组模拟】删边(delete) 题解

    题意简述

    给一棵树删边,每次删的代价为这条边所连的两个点的子树中最大点权值。

    求删光的最小代价。

    (nle100000).

    Solution

    正着思考发现没有什么好的思路,贪心的话会后效性。不妨反过来考虑

    这时题目变成了:给(n)个点,每次连通两个点集,代价为两个点集中最大点权之和。

    例如这个图

    image-20201130125545031

    首先,每个点都是独立的。

    那么你会先加入(1-2)还是(2-3)呢?

    如果先加入(2-3),代价为(2+3),接下来再加入点(1)时,(2-3)所产生的贡献是(3)

    如果而后还有一些集合需要并进来时,当前集合所产生的贡献为(3),很大很浪费。

    所以,我们要让点权大的点以后再合并,点权小的点先合并。

    所以初始化时先把边权设为其所连两点的点权中更大的那一个。对所有边按照边权排序,再用类似并查集的方法合并同时维护集合中的最大点权。

    以上。

    Code

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define IL inline
    #define re register
    #define LL long long
    #define ULL unsigned long long
    #ifdef TH
    #define debug printf("Now is %d
    ",__LINE__);
    #else
    #define debug
    #endif
    using namespace std;
    
    template<class T>inline void read(T&x)
    {
    	char ch=getchar();
    	int fu;
    	while(!isdigit(ch)&&ch!='-') ch=getchar();
    	if(ch=='-') fu=-1,ch=getchar();
    	x=ch-'0';ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	x*=fu;
    }
    inline int read()
    {
    	int x=0,fu=1;
    	char ch=getchar();
    	while(!isdigit(ch)&&ch!='-') ch=getchar();
    	if(ch=='-') fu=-1,ch=getchar();
    	x=ch-'0';ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*fu;
    }
    int G[55];
    template<class T>inline void write(T x)
    {
    	int g=0;
    	if(x<0) x=-x,putchar('-');
    	do{G[++g]=x%10;x/=10;}while(x);
    	for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('
    ');
    }
    int n,f[100010],mx[100010],a[100010];
    LL ans;
    int getf(int x)
    {
    	if(f[x]==x) return x;
    	return f[x]=getf(f[x]);
    }
    void merge(int x,int y)
    {
    	x=getf(x);
    	y=getf(y);
    	if(x!=y)
    	{
    		ans+=mx[x]+mx[y];
    		mx[x]=max(mx[x],mx[y]);
    		f[y]=x;
    	}
    }
    struct edge
    {
    	int x,y;
    	edge(int xx=0,int yy=0){x=xx,y=yy;}
    //	int v()const{return max(a[x],a[y]);}
    	bool operator<(const edge & z)const
    	{
    		return max(a[x],a[y])<max(a[z.x],a[z.y]);
    	}
    };
    vector<edge>e;
    int main()
    {
    //	freopen("delete.in","r",stdin);
    //	freopen("delete.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++) f[i]=i,mx[i]=a[i]=read();
    	for(int i=1;i<n;i++) e.push_back(edge(read(),read()));
    	sort(e.begin(),e.end());
    	for(unsigned i=0;i<e.size();i++)
    	{
    		merge(e[i].x,e[i].y);
    	}
    	cout<<ans;
    	return 0;
    }
    

    End

    差点抱玲了(玲酱这么可爱为什么不抱抱呢?大雾),还好最后想到了逆向思维。

    考试之后,( exttt{lc})的算法是(O(n))的,让我大开眼界呢!

    评测机出锅了,image-20201130130909649

    image-20201130130932477

    仿佛回到了去年暑假的那些日子呢

    image-20201130131020655


    不会吧不会吧,不会是个人写的都是(O(n))吧!

  • 相关阅读:
    更新自己知识的网站
    CRM IFD 部署在同一台服务器上遇到的错误
    Dynamics CRM 修改Excel 最大导出记录限制及 最大上传文件限制
    CRM 插件奇怪的报错
    单实例,当MongoDB单表数据文件太大导致写入速度变慢
    MongoDB分片实战
    SpringCloud使用feign时的复杂参数传递(转)
    99%的人都理解错了HTTP中GET与POST的区别(转)
    MySQL 数据导入 Unknown MySQL server host 'localhost'
    会员积分体系设计思路(转)
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/14060738.html
Copyright © 2011-2022 走看看