题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238

看了半天...

首先,想要知道每条边删除之后的替代中最小的那个;

反过来看,每条不在 MST 上的边如果加入,会对一条路径产成影响,具体来说,就是这条路径上的所有边在被删除后,可以考虑用这条非 MST 边替代;

于是就可以用树剖,对每条非 MST 边,维护一下路径上的最小值;

于是写了一下,但WA了,仔细看看,mn 和 lzy 更新的地方似乎有点不太对,比如没有更新 mn 也可以更新 lzy 什么的...(因为 mn 还被左右儿子更新,所以可能比 lzy 更小...)

反正是取min,标记永久化很方便呢(干脆没有 lzy ),于是又跟 Narh 学了一下 mn 标记永久化的写法。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;
int const xn=,xm=1e5+,inf=0x3f3f3f3f;
int n,m,hd[xn],ct,nxt[xn<<],to[xn<<],dep[xn],siz[xn],son[xn],dfn[xn],top[xn],fa[xn],tim;
int mn[xn<<],lzy[xn<<],ans;
bool use[xm],fl;
struct N{int u,v,w,id;}e[xm];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
bool cmp(N x,N y){return x.w<y.w;}
bool cmp2(N x,N y){return x.id<y.id;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int x)
{
dep[x]=dep[fa[x]]+; siz[x]=;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa[x])continue;
fa[u]=x; dfs(u); siz[x]+=siz[u];
if(siz[u]>siz[son[x]])son[x]=u;
}
}
void dfs2(int x)
{
dfn[x]=++tim;
if(son[x])top[son[x]]=top[x],dfs2(son[x]);
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa[x]||u==son[x])continue;
top[u]=u; dfs2(u);
}
}
void pushdown(int x)
{
if(lzy[x]==-)return;
if(lzy[x]<mn[ls])mn[ls]=lzy[x],lzy[ls]=lzy[x];
if(lzy[x]<mn[rs])mn[rs]=lzy[x],lzy[rs]=lzy[x];
lzy[x]=-;
}
void update(int x,int l,int r,int L,int R,int d)
{
// if(l>=L&&r<=R){if(d<mn[x])mn[x]=d,lzy[x]=d; return;}
// pushdown(x);
if(l>=L&&r<=R){mn[x]=min(mn[x],d); return;}
// mn[x]=min(mn[x],d);
if(mid>=L)update(ls,l,mid,L,R,d);
if(mid<R)update(rs,mid+,r,L,R,d);
// mn[x]=min(mn[ls],mn[rs]);
}
void change(int x,int y,int d)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(,,n,dfn[top[x]],dfn[x],d);
x=fa[top[x]];
}
if(x==y)return;
if(dep[x]<dep[y])swap(x,y);
update(,,n,dfn[y]+,dfn[x],d);
}
int query(int x,int l,int r,int pos)
{
if(l==r)return mn[x];
// pushdown(x);
// if(pos<=mid)return query(ls,l,mid,pos);
// else return query(rs,mid+1,r,pos);
if(pos<=mid)return min(mn[x],query(ls,l,mid,pos));
else return min(mn[x],query(rs,mid+,r,pos));
}
int main()
{
n=rd(); m=rd();
for(int i=,x,y,z;i<=m;i++)e[i].u=rd(),e[i].v=rd(),e[i].w=rd(),e[i].id=i;
sort(e+,e+m+,cmp);
for(int i=;i<=n;i++)fa[i]=i; int cnt=;
for(int i=;i<=m;i++)
{
int x=find(e[i].u),y=find(e[i].v);
if(x==y)continue;
add(e[i].u,e[i].v); add(e[i].v,e[i].u); ans+=e[i].w;
fa[x]=y; cnt++; use[e[i].id]=;//id
if(cnt==n-)break;
}
if(cnt<n-)fl=;
if(!fl)//省时
{
fa[]=; dfs(); top[]=; dfs2();
memset(mn,0x3f,sizeof mn); memset(lzy,-,sizeof lzy);
sort(e+,e+m+,cmp2);
for(int i=;i<=m;i++)
{
if(use[i])continue;
change(e[i].u,e[i].v,e[i].w);
}
}
int q=rd();
for(int i=,x;i<=q;i++)
{
x=rd();
if(fl){puts("Not connected"); continue;}
if(!use[x]){printf("%d\n",ans); continue;}
int k=query(,,n,max(dfn[e[x].u],dfn[e[x].v]));
if(k==inf)puts("Not connected");
else printf("%d\n",ans-e[x].w+k);
}
return ;
}

bzoj 2238 Mst —— 树剖+mn标记永久化的更多相关文章

  1. bzoj 2238 Mst——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238 一条非树边可以对一条链的树边产生影响.注意是边,所以把边下放到点上,只要跳 top 时 ...

  2. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  3. bzoj 2238 Mst

    显然先求出最小生成树 如果删的是非树边就不用管,还是能取最小生成树 如果删的是树边就有非树边可以替代它 反向考虑,每条非树边可以替代最小生成树上一条路径的边 所以树剖加线段树,对每条非树边在树上更新对 ...

  4. BZOJ 2238: Mst DFS序+KDtree

    明明可以用二维数点来做啊,网上为什么都是树剖+线段树呢 ? code: #include <cstdio> #include <cstring> #include <al ...

  5. BZOJ 1798 (线段树||分块)的标记合并

    我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...

  6. BZOJ 3083: 遥远的国度 (树剖+线段树)

    传送门 解题思路 前两个操作都比较基础.对于第三个操作分类讨论一下,首先如果当前根不是要操作点的子树,那么就无影响,直接查询操作点的子树即可.第二种是当前根是操作点的子树,那就找到当前根到操作点这条链 ...

  7. BZOJ 3110 线段树套线段树

    思路: 外围一个权值线段树 里面是个区间线段树 搞一个标记永久化 //By SiriusRen #include <cstdio> #include <cstring> #in ...

  8. [HNOI2015]开店(树剖+主席树+标记永久化)

    听说正解点分树?我不会就对了 此题是 \([LNOI2014]LCA\) 强化版,也是差分一下,转化为区间加区间和 不过权值有大小要求,那么我们按照权值排序,依次加入主席树,询问的时候 \(lower ...

  9. bzoj 1513 POI2006 Tet-Tetris 3D 二维线段树+标记永久化

    1511: [POI2006]OKR-Periods of Words Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 351  Solved: 220[S ...

随机推荐

  1. 让win7任务条上的文件夹打开是c,d,e,f而不是库

    如果资源管理器是打开的,则右键点击资源管理器的图标,在跳出的菜单中,右键点击“Windows资源管理器”,选择“属性”. 在“快捷方式’选项卡,“目标”一栏,默认的是 %windir%\explore ...

  2. java多线程02-----------------synchronized底层实现及JVM对synchronized的优化

    java多线程02-----------------synchronized底层实现及JVM对synchronized的优化 提到java多线程,我们首先想到的就是synchronized关键字,它在 ...

  3. Go --- GC优化经验

    不想看长篇大论的,这里先给个结论,go的gc还不完善但也不算不靠谱,关键看怎么用,尽量不要创建大量对象,也尽量不要频繁创建对象,这个道理其实在所有带gc的编程语言也都通用. 想知道如何提前预防和解决问 ...

  4. centos的python2.6.x升级到python2.7.x方法;python2.6.x的版本就不要用了

    python2.6.x的版本,现在使用的很多插件都不支持了.所以如果你的centos还是使用的2.6.x版本,不要犹豫,赶紧升级到2.7.x版本 1.所谓升级,就是再安装一个python2.7.x版本 ...

  5. BUPT复试专题—List(2015)

    题目描述 在该LIST上实现3种操作 1.append x在该LIST末尾添加x,x是32位整数 2.pop删除该LIST末尾的数 3.find i寻找第i个数,若i为负数表示寻找倒数第i个数,例如i ...

  6. chrome 的onbeforeunload事件没有触发

    onbeforeunload event is not working when user not click inside the body of page 0down votefavorite   ...

  7. EasyDarwin开源手机直播方案:EasyPusher手机直播推送,EasyDarwin流媒体server,EasyPlayer手机播放器

    在不断进行EasyDarwin开源流媒体server的功能和性能完好的同一时候,我们也配套实现了眼下在安防和移动互联网行业比較火热的移动端手机直播方案,主要就是我们的 EasyPusher直播推送项目 ...

  8. JS 计算2个日期相差的天数

    <span style="font-size:18px;">function getDays(strDateStart,strDateEnd){ var strSepa ...

  9. ansible 基本命令学习与踩坑

    1. 命令行参数 -v,–verbose 详细模式,如果命令执行成功,输出详细的结果(-vv –vvv -vvvv) -i PATH,–inventory=PATH 指定host文件的路径,默认是在/ ...

  10. CSDN-markdown编辑器之从线上导入Markdown文件

      CSDN-markdown编辑器支持从线上导入Markdown文件的功能,假设你用其他支持Markdown的编辑器在网上写了博客文章或说明档,想公布到CSDN博客中,就能够使用本功能非常方便的完毕 ...