首页 > 其他分享 >CF671D Roads in Yusland 题解

CF671D Roads in Yusland 题解

时间:2023-08-07 20:11:07浏览次数:67  
标签:rt num 题解 ll CF671D tag Roads include 节点

题目链接

题目要求我们求出选出若干条路径并最小化花费,如果这是在链上,我们可以考虑直接枚举每条路径的右端点 dp,那树呢?把路径剖分整个覆盖的集合就不一定连续了,没法 dp,况且题目里给了很强的条件:路径一定是从孩子到祖先,硬转链用不上这个性质,貌似不太对。

上述思考启发我们利用树的形态设计算法,而利用节点的子树分割成子问题是一个通常的思考方向,我们从此处入手,考虑如果要覆盖一棵树需要什么条件,首先,根节点的每棵子树必须被覆盖,并且还要有一条能向外延伸的边以覆盖连接根节点和子树根节点的边。

考虑设计 dp 以维护上述条件,为了维护前者,我们可以钦定每个节点的状态所选择的解中子树全部被覆盖;而后者,由于子树内所有节点的祖先并都在固定的一条链上,我们可以添加一维确定向外延伸的长度。具体地,我们设 \(f_{u,j}\) 表示完全覆盖节点 \(u\) 的子树且向外延伸了 \(j\) 个长度的最小花费。

转移是显然的,设 \(g_u=\min f_{u,j}\),则 \(f_{u,j}=\min \{f_{v,j}\}+\sum_{k\in son(v)} g_k -g_v\)。这个做法是 \(O(n^2)\) 的。

由于转移比较简单,我们考虑能不能用数据结构维护第二维,需要支持合并取 min 和全局加,用线段树合并就可以维护,时间和空间复杂度都是 \(O((n+m)\log n)\) 的。

但是本题空间复杂度限制比较紧,注意到线段树中有很多没有用的节点,并且不能动态调整空间。考虑换成平衡树,每个节点储存二元组 \((j,cost)\) 表示向上延伸 \(j\) 距离花费 \(cost\),全局加可以直接打标记,合并可以直接启发式合并,全部插到里面就行,注意为了保证复杂度,如果有向上延伸相同距离的状态我们只能保留一个。

问题是取 min,由于刚才我们已经要求平衡树按第一维排序,我们不好直接求全局 min,但是注意到如果一个状态相比于另一个能覆盖更前面的边但是花费也更小,我们不必保留另一个状态,因此在满足一维排好序的情况下另一位也排好了。平衡树可以用 set,时间复杂度 \(O((n+m)\log^2 n)\),但是空间复杂度变成了线性,可以通过。

// Problem: Roads in Yusland
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF671D
// Memory Limit: 250 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector> 
#include<set>
#define ll long long
#define N 300005
using namespace std;
ll read(){
	ll x=0;char ch=getchar();
	while(ch<'0' || ch>'9') ch=getchar();
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x;
}
ll e,head[N<<1],nex[N<<1],to[N<<1],dep[N],tag[N],rt[N];
struct Node{
	ll num,val;
	bool operator <(const Node &x)const{
		return num>x.num;
	}
};
vector<Node> E[N];
set<Node> t[N];
void add(ll u,ll v){
	to[++e]=v;nex[e]=head[u];head[u]=e;
	to[++e]=u;nex[e]=head[v];head[v]=e;
}
ll flag;
void insert(ll u,ll num,ll val){
	if(t[u].size()==0){t[u].insert((Node){num,val});return;}
	auto it=t[u].lower_bound((Node){num,val});
	if(it==t[u].end() || (it->num)!=num){
		if(it!=t[u].end() && it->val<=val)return;
		if(it==t[u].begin()){t[u].insert((Node){num,val});return;}
		auto itr=it,itl=it;
		while(itl!=t[u].begin()){
			itl--;if(itl->val<val){itl++;break;}
		}
		if(itl!=itr)t[u].erase(itl,itr);
		t[u].insert((Node){num,val});return;
	}
	if(it->val<=val) return;
	it++;auto itr=it;it--;
	while(it!=t[u].begin()){
		it--;if(it->val<val){it++;break;}
	}
	t[u].erase(it,itr);
	t[u].insert((Node){num,val});
}
void dfs(ll u,ll fa){
	rt[u]=u;
	ll tot=0;dep[u]=dep[fa]+1;
	for(ll i=head[u];i;i=nex[i]){
		ll v=to[i];if(v==fa) continue;
		dfs(v,u);if(flag) return;
		if(t[rt[v]].size()==0){flag=1;return;}
		if((t[rt[v]].begin()->num)>dep[u])t[rt[v]].erase(t[rt[v]].begin());
		if(t[rt[v]].size()==0){flag=1;return;}
		tot+=(t[rt[v]].begin()->val+tag[v]);tag[v]=-(t[rt[v]].begin()->val);
	}
	ll tmp=300001;
	for(ll i=head[u];i;i=nex[i]){
		ll v=to[i];if(v==fa) continue;
		if(t[rt[v]].size()>t[rt[u]].size()){tmp=v;rt[u]=rt[v];tag[u]=tot+tag[v];}
	}
	for(ll i=head[u];i;i=nex[i]){
		ll v=to[i];if(v==fa || rt[v]==rt[u]) continue;
		for(auto it=t[rt[v]].begin();it!=t[rt[v]].end();it++){
			insert(rt[u],it->num,it->val+tag[v]-tag[tmp]);
		}
	}
	for(ll i=0;i<E[u].size();i++){
		insert(rt[u],dep[E[u][i].num],E[u][i].val-tag[tmp]);
	}
}
int main(){
	ll n,m,u,v,w;n=read();m=read();
	for(ll i=1;i<n;i++){u=read();v=read();add(u,v);}
	for(ll i=1;i<=m;i++){
		u=read();v=read();w=read();E[u].push_back((Node){v,w});
	}
	if(n==1){cout<<0;return 0;}
	dfs(1,0);
	if(flag) cout<<-1;
	else cout<<(t[rt[1]].begin()->val)+tag[1];
	return 0;
}

标签:rt,num,题解,ll,CF671D,tag,Roads,include,节点
From: https://www.cnblogs.com/eastcloud/p/17612619.html

相关文章

  • “科大国创杯”2023 年安徽省青少年信息学科普日活动 简要题解
    “科大国创杯”2023年安徽省青少年信息学科普日活动简要题解小学组T1grade直接累加即可。不需要按百分比算(也就是别/100),那样可能会出现一些浮点数误差。T2order暴力枚举t就可以了T3string答案即为cnt4+cnt5-cnt20。注意到对于一个数,我们只关心其个位和十位就......
  • 打开电脑中应用程序及问题解决方案
    1、使用os.system()函数:示例代码importosos.system("notepad.exe")这将在Windows系统上打开记事本应用程序。2、使用subprocess示例代码:importsubprocesssubprocess.Popen(['notepad.exe'])3、使用webbrowser示例代码:importwebbrowserwebbrowser.open('http://www.goog......
  • 【题解】 Pattern Matching in A Minor "Low Space" CCPC Mianyang 2022
    https://vjudge.net/contest/573644#problem/K字符串匹配,但卡空间。考虑哈希做法,不妨把\(s\)每\(20000\)个字符哈希成一个字符,于是\(s\)长度只有\(500\),可以跑个KMP。于是对于\(t\),我们只需要同时维护\(20000\)个KMP的指针。但如果字符串长度不是\(20000\)的倍......
  • P9498 「RiOI-2」equals题解
    题目传送门:P9498「RiOI-2」equals-洛谷|计算机科学教育新生态(luogu.com.cn)这是洛谷月赛Div.2T3,由于我比较菜,只能赛场上切到T3(T4是黑。),开题我们很容易就看出这道题首先需要初始化每个点到根节点的最短路,而且边权都为1,所以我们先无脑打一个堆优化的dijkstra,剩下的就是处......
  • P1005 [NOIP2007 提高组] 矩阵取数游戏题解
    题面传送门:P1005[NOIP2007提高组]矩阵取数游戏-洛谷|计算机科学教育新生态(luogu.com.cn)分析题目可知,这道题是一道求最值的问题,第一次看题没有认真读题,以为是每次只在某一行中选一个数,于是想了半天无果。重新读题才发现每次需要每行都取,那么这就很简单了,相当于在每一行......
  • 洛谷 P1336 最佳课题选择 题解
    P1336最佳课题选择题解状态:考虑\(f_{i,j}\)表示前\(i\)种论文里面,一共写了\(j\)篇,的最少花费时间。转移策略:我们一次考虑每一种论文写多少篇。假设写\(k\)篇,\(k\in[0,j]\cap\mathbb{Z}\),有转移方程:\[f_{i,j}=min(f_{i-1,j-k}+cost(i,k)),k\in[0,j]\cap\mathbb{......
  • RTSP/Onvif视频服务器LntonNVR(源码版)视频平台无法通过Onvif控制摄像头云台的问题解决
    LntonNVR视频边缘计算网关平台是我们推出的软硬一体的视频平台,既有软件版本,又有硬件版本。LntonNVR与摄像头连接时,可以通过平台自带的Onvif探测进行设备探测、连接,还能实现对摄像头的PTZ云台控制,包括镜头转向、变焦等操作。通过Onvif控制云台是非常实用的功能,在很多用户实际项目中......
  • 国标GB28181视频平台LntonGBS(源码版)国标平台出现录像无法播放并存在RTMP重复推流现象
    LntonGBS国标视频云服务通过支持国标GB28181协议,实现了设备接入、实时监控直播、录像、语音对讲、云存储、告警、级联等功能。同时,它还支持将接入的视频流以多种格式(包括RTSP、RTMP、FLV、HLS、WebRTC)进行全终端、全平台分发,实现了无插件播放在Web浏览器、手机浏览器、微信端、PC客......
  • zookeeper常见问题解决
     注意:自zk3.5.5版本以后,已编译的jar包,尾部有bin标识,应该使用的是apache-zookeeper-3.x.x-bin.tar.gz 错误一:Startingzookeeper…FAILEDTOSTART版本问题,自3.5以上的版本,随着版本的更新,3.5版本以后的压缩包分成了两种我们需要使用文件名带有bin的那个压缩包,例如:ap......
  • [ABC313] C~E 题解
    [ABC313]C~E题解C-ApproximateEqualization2让所有的数字都尽量接近平均数,先算出平均数,然后把所有数字分成两份,一份要加,一份要减,因为平均数有余数,余数肯定给最大的几个,所以这样计算总共需要加减多少个,然后在加减里面取\(\max\)即可。时间复杂度:\(O(n\logn)\)#include......