洛谷 2680 运输计划 题解

news/2024/11/22 22:20:28/

博客观赏效果更佳

题意简述

n n n个点的边带权树,给 m m m条关键的链。把树上一条边的权值变为0,使得 m m m条链的和中,最大值最小。 n , m < = 1 e 5 n,m<=1e5 n,m<=1e5

思路

二分最大值 k k k。现在考虑如何检验一个 k k k

找到所有链和 > k >k >k的链,设这里面最长的链长度为 S S S,有 C C C条这样的链。用树链剖分找到被所有 C C C条链都覆盖的边。设边权为 w w w,如果 S − w < = k S-w<=k Sw<=k,又因为这条边被所有和 > k >k >k的链都覆盖了,所以,将这条边边权设为 0 0 0,就珂以把所有和 > k >k >k的链修♂正回来。那就满足条件了,检验结果为true。

然后就这样二分即珂。

关于如何求被所有链都覆盖的边

如果您足够明智,跳过这个部分好了。

开一颗临时的树,所有边权为 0 0 0,树链剖分维护:对于所有和 > k >k >k的链 ( a , b ) (a,b) (a,b),在链上的边权都+1。

然后只要找边权 = C =C =C的边即珂。

但是树链剖分维护的是点权,怎么把边权转化成点权呢?只要把一条边的权值,记录在这条边的儿子上即珂。然后我们对于链 ( u , v ) (u,v) (u,v)作加法操作的时候,记得把 L C A ( u , v ) LCA(u,v) LCA(u,v)的操作给撤回掉(就是减掉),因为这个是多算的。

代码


#include <bits/stdc++.h>using namespace std;
namespace Flandre_Scarlet
{#define int long long #define N 355555#define F(i,l,r) for(int i=l;i<=r;++i)#define D(i,r,l) for(int i=r;i>=l;--i)#define Fs(i,l,r,c) for(int i=l;i<=r;c)#define Ds(i,r,l,c) for(int i=r;i>=l;c)#define MEM(x,a) memset(x,a,sizeof(x))#define FK(x) MEM(x,0)#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))#define p_b push_back#define sz(a) ((int)a.size())#define iter(a,p) (a.begin()+p)class Graph //图{public:int head[N];int EdgeCount;struct Edge{int To,Label,Next;}Ed[N<<1];void clear(int _V=N,int _E=N<<1) {memset(Ed,-1,sizeof(Edge)*(_E));memset(head,-1,sizeof(int)*(_V));EdgeCount=-1;}void AddEdge(int u,int v,int w=1){Ed[++EdgeCount]=(Edge){v,w,head[u]};head[u]=EdgeCount;}void Add2(int u,int v,int w=1) {AddEdge(u,v,w);AddEdge(v,u,w);}int Start(int u) {return head[u];}int To(int u){return Ed[u].To;}int Label(int u){return Ed[u].Label;}int Next(int u){return Ed[u].Next;}}G;class BIT //树状数组{public:int tree[N];int len;void BuildTree(int _len){len=_len;FK(tree);}void Add(int pos,int val=1){for(int i=pos;i<=len;i+=(i&(-i))){tree[i]+=val;}}void RAdd(int l,int r,int val=1) {Add(l,val);Add(r+1,-val);}int Query(int pos){int ans=0;for(int i=pos;i>0;i-=(i&(-i))){ans+=tree[i];}return ans;}}T;void R1(int &x){x=0;char c=getchar();int f=1;while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();x=(f==1)?x:-x;}int n,m;int a[N],b[N];void Input(){R1(n),R1(m);G.clear();int u,v,w;F(i,1,n-1) R1(u),R1(v),R1(w),G.Add2(u,v,w);F(i,1,m) R1(a[i]),R1(b[i]);}int fa[N],deep[N],size[N],dis[N];int son[N],val[N]; //val[i]: i和fa[i]之间的边权,就是上面说的,“把边权记录在该边的儿子上”//dis[i]: i到根节点的带权距离(就是经过的所有边权的和)void DFS1(int u,int f){fa[u]=f; deep[u]=(u==f)?0:deep[f]+1;dis[u]=(u==f)?0:dis[f]+val[u]; size[u]=1;son[u]=-1;int Max=-1;Tra(i,u){int v=__v;if (v!=f){val[v]=G.Label(i);DFS1(v,u);size[u]+=size[v];if (size[v]>Max) {Max=size[v];son[u]=v;}}}}int DFSid[N],top[N],Time=0;void DFS2(int u,int topu){DFSid[u]=++Time;top[u]=topu;if (son[u]==-1) return;DFS2(son[u],topu);Tra(i,u){int v=__v;if (v!=fa[u] and v!=son[u]) DFS2(v,v);}}int LCA(int u,int v) //树剖求LCA (真的只是个LCA,没别的){while(top[u]!=top[v]){if (deep[top[u]]<deep[top[v]]) swap(u,v);u=fa[top[u]]; }return deep[u]<deep[v]?u:v;}int PathLen(int u,int v){return dis[u]+dis[v]-2*dis[LCA(u,v)];} //求链<u,v>的带权长度void PathAdd(int u,int v,int w=1){while(top[u]!=top[v]){if (deep[top[u]]<deep[top[v]]) swap(u,v);T.RAdd(DFSid[top[u]],DFSid[u],w);u=fa[top[u]];}if (deep[u]>deep[v]) swap(u,v);T.RAdd(DFSid[u],DFSid[v],1); //常规树剖操作int L=LCA(u,v);T.RAdd(DFSid[L],DFSid[L],-1); //把多算的减掉}int Maxlen;bool cxk(int k){T.BuildTree(n);int cnt=0;F(i,1,m) if (PathLen(a[i],b[i])>k) //如果这条边权值过大{++cnt;PathAdd(a[i],b[i],1);}F(i,1,n) {if (T.Query(DFSid[i])==cnt and Maxlen-val[i]<=k) // T.Query(DFSid[i])==cnt表示i和fa[i]这条边被所有的该修正的边覆盖了//Maxlen-val[i]<=k表示,我能修正所有该修正的边{return true; //所以这个时候把(i,fa[i])这条边权值设为0,就满足条件了。}}return false;}void Soviet(){DFS1(1,1);DFS2(1,1);Maxlen=-1; F(i,1,m) Maxlen=max(Maxlen,PathLen(a[i],b[i])); //Maxlen珂以提前求,少掉一个mT.BuildTree(n);int l=0,r=1e9; //注意:l=0(我一开始就是这样写的,没WA过,但是我猜写l=1会WA几个点)while(l<r){int mid=(l+r)>>1;if (cxk(mid)) r=mid;else l=mid+1;}printf("%lld\n",l);}#define Flan voidFlan IsMyWife(){Input();Soviet();}#undef int //long long 
}
int main(){Flandre_Scarlet::IsMyWife();getchar();getchar();return 0;
}

http://www.ppmy.cn/news/163483.html

相关文章

HDU 2680

这是一道最短路&#xff0c;求多点之间的距离&#xff0c;我一开始用的是Floyd,但发现超时了&#xff0c;后来看了大牛的博客才发现一种新的方法&#xff0c;就是设出一个虚点&#xff0c;使这个虚点到要开始点的距离都为0&#xff0c;然后用Dijkstra&#xff0c;具体看代码&am…

服务器型号E52680,服务器配置e5-2680v3

服务器配置e5-2680v3 内容精选 换一换 删除指定ID的后端云服务器。删除后端云服务器后&#xff0c;不会再建立新的连接&#xff0c;但是原本建立在这个后端云服务器上的长连接还会保持。DELETE /v2.0/lbaas/pools/{pool_id}/members/{member_id}无无请求样例 删除后端云服务器D…

典型的dijkstra HDU 2680 Choose the best route

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2680 题目大意&#xff1a;一个笨蛋要坐车去朋友家&#xff0c;但坐车呕吐&#xff0c;所以想在最短时间内到达。 测试数据意思&#xff1a; 第一行三个数&#xff1a;n(车站的个数&#xff0c;n<1000) …

intel Xeon(R) CPU E5-2650 v2 性能测试报告

intel Xeon(R) CPU E5-2650 v2 性能测试报告 一.测试背景: 验证Xeon(R) CPU E5-2650 v2 的性能,和基于KVM的openstack平台的处理能力和稳定性。镜像、虚拟机用horizon控制台管理,按照测试方法从horizon开启虚拟机,…

HDU-2680,Choose the best route(Dijkstra)

Problem Description&#xff1a; One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are …

微软CVE-2023-28252漏洞

微软内核提权0day漏洞 4月12号&#xff0c;微软发布了最新的漏洞补丁程序&#xff0c;此次公告中的内核提权漏洞CVE-2023-28252&#xff0c;由安恒信息、卡巴斯基及Mandiant公司同时捕获&#xff0c;这也是安恒信息成功捕获的第4枚在野内核提权0day&#xff01; 据卫兵实验室…

服务器型号E52680,e5 2680v3 云服务器

e5 2680v3 云服务器 内容精选 换一换 将云服务器加入云服务器组。添加成功后&#xff0c;该云服务器与云服务器组中的其他成员尽量分散地创建在不同主机上。仅支持添加虚拟化类型为KVM的弹性云服务器。当前只支持反亲和性策略&#xff0c;即同一云服务器组中的弹性云服务器分散…

百练_2680:化验诊断

描述 下表是进行血常规检验的正常值参考范围&#xff0c;及化验值异常的临床意义&#xff1a; 给定一张化验单&#xff0c;判断其所有指标是否正常&#xff0c;如果不正常&#xff0c;统计有几项不正常。化验单上的值必须严格落在正常参考值范围内&#xff0c;才算是正常。正常…