【CF671D】尤斯兰的道路
题目
题目链接:https://codeforces.com/problemset/problem/671/D
给定一棵\(n\)个点的以\(1\) 为根的树。
有\(m\)条路径\((x,y)\),保证\(y\)是\(x\)或\(x\)的祖先,每条路径有一个权值。
你要在这些路径中选择若干条路径,使它们能覆盖每条边,同时权值和最小。
《10^5\)。时报》
思路
设\(f[x]\)表示覆盖点\(x\)子树内所有边以及\(x\)与其父亲的边的最小代价。
但是很明显\(f[x]\)不能简单转移。因为有可能花更多代价,覆盖\(x\)的祖先更多,这种情况是可能最优的。
所以可以对每一个点维护一个堆,存可能的最优解。
考虑点\(y\)怎么转移到其父亲\(x\)。对于\(y\)的堆中一个代价为\(k\)的方案,合并到\(x\)后,其代价应该是\(k \\ sum _ { z \\ in \\ text { son }(x),z \\ neq y \u f[z]\)。
也就是说,\(y\)的所有方案只需要同时加上一个常数,然后扔到\(x\)的堆里就好了。直接上左偏树,然后需要搞一个子树加的标记。
但是当某一个方案覆盖不到\(x\)与其父亲的边的时候,这个方案就需要删掉了。在每次合并完后不断判断堆顶是否需要删掉即可。
新建一个虚根连向\(1\),再加一条代价为\(0\) 的路径,最后输出虚根的\(f\)即可。
时间复杂度\(0(n \ log m)\)。
代码
#包含位/stdc .h
#定义国会议员制作对
#首先定义船方不负担装货费用
#定义硒秒
使用命名空间标准;
typedef长ll长
常量整数N=300010
整数n,m,tot,头[N],rt[N],副[N];
ll f[N];
布尔标志;
vectorpairint,int a[N];
结构边缘
{
(同Internationalorganizations)国际组织紧挨着;
} e[N * 2];
void add(int from,int to)
{
e[ tot]=(edge){head[from],to };
从头开始。
}
结构左树
{
int tot,dis[N],pos[N],lc[N],RC[N];
懒惰的;
int insert(pairint,int b)
{
tot val[tot]=b . se;pos[tot]=b . fi;
返回小孩
}
无效下推(int x)
{
如果(懒惰[x])
{
if (lc[x]) val[lc[x]]=lazy[x],lazy[LC[x]]=lazy[x];
if (rc[x]) val[rc[x]]=lazy[x],lazy[RC[x]]=lazy[x];
lazy[x]=0;
}
}
int merge(int x,int y)
{
if(!x ||!y)返回x | y;
下推;下推(y);
if(val[x]val[y]| |(val[x]==val[y]xy))swap(x,y);
rc[x]=merge(rc[x],y);
if(dis[RC[x]]dis[LC[x]]交换(LC[x],RC[x]);
dis[x]=dis[RC[x]]1;
返回x;
}
int pop(int x)
{
下推;
返回合并(lc[x],RC[x]);
}
}点亮;
无效dfs(int x,int fa)
{
dep[x]=dep[fa]1;
for(int I=0;i(int)a[x].size();(一)
rt[x]=lit.merge(rt[x],lit)。插入(a[x][I]);
for(int I=head[x];~我;i=e[i]。下一个)
{
int v=e[i].去;
if (v!=fa)
{
dfs(v,x);f[x]=f[v];
如果(标志)返回;
真实的懒惰[rt[v]]-=f[v];真实的val[rt[v]]-=f[v];
rt[x]=lit.merge(rt[x],rt[v]);
}
}
真实的lazy[rt[x]]=f[x];真实的val[rt[x]]=f[x];
而(rt[x]dep[lit]。pos[rt[x]]=dep[x])
rt[x]=点亮。pop(rt[x]);
if(!rt[x]){ flag=1;返回;}
f[x]=升。val[rt[x]];
}
int main()
{
memset(head,-1,sizeof(head));
scanf('%d%d ',n,m);
for (int i=1,x,y;在;(一)
{
scanf('%d%d ',x,y);
添加(x,y);添加(y,x);
}
n;add(n,1);
for (int i=1,x,y,z;I=m;(一)
{
scanf('%d%d%d ',x,y,z);
a[x].push_back(mp(y,z));
}
a[1].push_back(mp(0,0));
真实的dis[0]=-1;dep[0]=-1;
dfs(n,0);
如果(标志)cout '-1 ';
else coutf[n];
返回0;
}
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/37483.html