这题在浴谷夏令营wyx在讲的最小生成树的时候提到过,但并没有细讲怎么写...

  这题可以用三种写法写,虽然只有两种能过。。。(倍增/倍增+并查集/树链剖分

  先跑出最小生成树,分类讨论,在MST上的边,考虑用可以对这条边有影响的(判断是否有影响同后面)不在MST上的边的最小值-1来更新,不在MST上的边u->v,考虑用MST上u到v的路径上的边的最大值-1来更新。

  显然用倍增就可以了,细节看代码。复杂度O(NlogN)

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=2e9;
struct poi{int x,y,z,pos;}a[maxn];
struct zs{int too,dis,pre;}e[maxn];
int n,m,x,y,z,tot;
int last[maxn],ans[maxn],mn[maxn][],mx[maxn][],f[maxn][],fa[maxn],d[maxn];
bool ty[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
bool cmp(poi a,poi b){return a.z<b.z;}
void add(int x,int y,int z){e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;}
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
void dfs(int x,int fa)
{
f[x][]=fa;d[x]=d[fa]+;
for(int i=last[x];i;i=e[i].pre)
if(e[i].too!=fa)
{
mx[e[i].too][]=e[i].dis;
dfs(e[i].too,x);
}
}
inline int query(int x,int y)
{
int ans=;
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y])ans=max(ans,mx[x][i]),x=f[x][i];
if(x==y)return ans;
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])ans=max(ans,max(mx[x][i],mx[y][i])),x=f[x][i],y=f[y][i];
return max(ans,max(mx[x][],mx[y][]));
}
void update(int x,int y,int delta)
{
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y])mn[x][i]=min(mn[x][i],delta),x=f[x][i];
if(x==y)return;
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])mn[x][i]=min(mn[x][i],delta),mn[y][i]=min(mn[y][i],delta),x=f[x][i],y=f[y][i];
mn[x][]=min(mn[x][],delta);mn[y][]=min(mn[y][],delta);
}
int main()
{
read(n);read(m);
for(int i=;i<=m;i++)read(a[i].x),read(a[i].y),read(a[i].z),a[i].pos=i;
for(int i=;i<=n;i++)fa[i]=i;
sort(a+,a++m,cmp);
for(int i=;i<=m;i++)
{
int fx=gf(a[i].x),fy=gf(a[i].y);
if(fx==fy)continue;
add(a[i].x,a[i].y,a[i].z);
add(a[i].y,a[i].x,a[i].z);
fa[fx]=fy;ty[i]=;
}
dfs(,);
for(int j=;j<;j++)for(int i=;i<=n;i++)mx[i][j]=max(mx[i][j-],mx[f[i][j-]][j-]),f[i][j]=f[f[i][j-]][j-];
memset(mn,0x7f,sizeof(mn));
for(int i=;i<=m;i++)
if(!ty[i])
{
ans[a[i].pos]=query(a[i].x,a[i].y)-;
update(a[i].x,a[i].y,a[i].z);
}
for(int j=;j>=;j--)for(int i=;i<=n;i++)mn[i][j-]=min(mn[i][j-],mn[i][j]),mn[f[i][j-]][j-]=min(mn[f[i][j-]][j-],mn[i][j]);
for(int i=;i<=m;i++)if(ty[i])ans[a[i].pos]=(d[a[i].x]>d[a[i].y]?mn[a[i].x][]:mn[a[i].y][])-;
for(int i=;i<=m;i++)printf("%d ",ans[i]>=inf?-:ans[i]);
return ;
}

  显然还可以写链剖。。但是两个log就TLE了。。。 MDZZ原来是我写残了,可以过的

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=2e9;
struct zs{int too,pre,dis;}e[maxn*];
struct tjm{int max,min,delta;}tree[maxn*];
struct poi{int x,y,z,pos;}a[maxn];
int n,m,x,y,z,tot,cnt;
int fa[maxn],fq[maxn],d[maxn],son[maxn],size[maxn],last[maxn],len[maxn],mx[maxn],w[maxn],ans[maxn],top[maxn];
bool ty[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
bool cmp(poi a,poi b){return a.z<b.z;}
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
void add(int x,int y,int z){e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;}
void dfs1(int x)
{
size[x]=;
for(int i=last[x];i;i=e[i].pre)
{
int too=e[i].too;
if(too==fq[x])continue;
fq[too]=x;
d[too]=d[x]+;
len[too]=e[i].dis;
dfs1(too);
if(size[too]>size[son[x]])son[x]=too;
size[x]+=size[too];
}
}
void dfs2(int x,int tp)
{
w[x]=++cnt;mx[cnt]=len[x];top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=last[x];i;i=e[i].pre)
if(e[i].too!=fq[x]&&e[i].too!=son[x])dfs2(e[i].too,e[i].too);
}
void pushup(int x,int l,int r)
{
if(l==r)return;
tree[x].min=min(tree[x<<].min,tree[x<<|].min);
tree[x].max=max(tree[x<<].max,tree[x<<|].max);
}
void pushdown(int x,int l,int r)
{
if(l==r)return;
if(tree[x].delta!=inf)
{
tree[x<<].min=min(tree[x<<].min,tree[x].delta);
tree[x<<|].min=min(tree[x<<|].min,tree[x].delta);
tree[x<<].delta=min(tree[x<<].delta,tree[x].delta);
tree[x<<|].delta=min(tree[x<<|].delta,tree[x].delta);
tree[x].delta=inf;
}
}
void build(int x,int l,int r)
{
if(l==r){tree[x].min=tree[x].delta=inf;tree[x].max=mx[l];return;}
int mid=(l+r)>>;
build(x<<,l,mid);build(x<<|,mid+,r);
tree[x].delta=inf;pushup(x,l,r);
}
void update(int x,int l,int r,int cl,int cr,int delta)
{
if(cl<=l&&r<=cr)tree[x].min=min(tree[x].min,delta),tree[x].delta=min(tree[x].delta,delta);
else
{
pushdown(x,l,r);
int mid=(l+r)>>;
if(cl<=mid)update(x<<,l,mid,cl,cr,delta);
if(cr>mid)update(x<<|,mid+,r,cl,cr,delta);
pushup(x,l,r);
}
}
int query(int x,int l,int r,int cx)
{
if(l==cx&&cx==r)return tree[x].min;
pushdown(x,l,r);
int mid=(l+r)>>,ret=inf;
if(cx<=mid)ret=query(x<<,l,mid,cx);
if(cx>mid)ret=query(x<<|,mid+,r,cx);
return ret;
}
int query2(int x,int l,int r,int cl,int cr)
{
if(cl<=l&&r<=cr)return tree[x].max;
pushdown(x,l,r);
int mid=(l+r)>>,ret=;
if(cl<=mid)ret=query2(x<<,l,mid,cl,cr);
if(cr>mid)ret=max(ret,query2(x<<|,mid+,r,cl,cr));
return ret;
}
int work(int x,int y,int delta)
{
int f1=top[x],f2=top[y],ans=;
while(f1!=f2)
{
if(d[f1]<d[f2])swap(x,y),swap(f1,f2);
if(delta!=-)update(,,n,w[f1],w[x],delta);
else ans=max(ans,query2(,,n,w[f1],w[x]));
x=fq[f1];f1=top[x];
}
if(x==y)return ans;
if(d[x]<d[y])swap(x,y);
if(delta!=-)update(,,n,w[son[y]],w[x],delta);
else return max(ans,query2(,,n,w[son[y]],w[x]));
return ans;
}
int main()
{
read(n);read(m);
for(int i=;i<=m;i++)read(a[i].x),read(a[i].y),read(a[i].z),a[i].pos=i;
sort(a+,a++m,cmp);
for(int i=;i<=n;i++)fa[i]=i;
for(int i=;i<=m;i++)
{
int fx=gf(a[i].x),fy=gf(a[i].y);
if(fx==fy)continue;
add(a[i].x,a[i].y,a[i].z);
add(a[i].y,a[i].x,a[i].z);
fa[fx]=fy;ty[i]=;
}
dfs1();dfs2(,);build(,,n);
for(int i=;i<=m;i++)
if(!ty[i])
{
ans[a[i].pos]=work(a[i].x,a[i].y,-)-;
work(a[i].x,a[i].y,a[i].z);
}
for(int i=;i<=m;i++)if(ty[i])ans[a[i].pos]=query(,,n,w[d[a[i].x]>d[a[i].y]?a[i].x:a[i].y])-;
for(int i=;i<=m;i++)printf("%d ",ans[i]==inf-?-:ans[i]);
return ;
}

  求最大值还是用倍增,求最小值的话,上面两种方法都不够快...

  注意到每条边只会被能更新它的最小值更新一次,于是就可以上并查集跳跳跳了,复杂度O(N)

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=,inf=2e9;
struct poi{int x,y,z,pos;}a[maxn],edge[maxn];
struct zs{int too,dis,pre;}e[maxn];
int n,m,x,y,z,tot,cnt,f1,f2,lastx,lasty;
int last[maxn],ans[maxn],mn[maxn][],mx[maxn][],f[maxn][],fa[maxn],d[maxn],v[maxn];
bool ty[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
bool cmp(poi a,poi b){return a.z<b.z;}
void add(int x,int y,int z){e[++tot].too=y;e[tot].dis=z;e[tot].pre=last[x];last[x]=tot;}
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
inline void dfs(int x,int fa)
{
f[x][]=fa;d[x]=d[fa]+;
for(int i=last[x];i;i=e[i].pre)
if(e[i].too!=fa)
{
mx[e[i].too][]=e[i].dis;
dfs(e[i].too,x);
}
}
inline int query(int x,int y)
{
int ans=;
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y])ans=max(ans,mx[x][i]),x=f[x][i];
if(x==y)return ans;
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])ans=max(ans,max(mx[x][i],mx[y][i])),x=f[x][i],y=f[y][i];
return max(ans,max(mx[x][],mx[y][]));
}
int main()
{
read(n);read(m);
for(int i=;i<=m;i++)read(a[i].x),read(a[i].y),read(a[i].z),a[i].pos=i;
for(int i=;i<=n;i++)fa[i]=i;
sort(a+,a++m,cmp);
for(int i=;i<=m;i++)
{
int fx=gf(a[i].x),fy=gf(a[i].y);
if(fx==fy)continue;
add(a[i].x,a[i].y,a[i].z);
add(a[i].y,a[i].x,a[i].z);
fa[fx]=fy;ty[i]=;
}
dfs(,);for(int j=;j<;j++)for(int i=;i<=n;i++)mx[i][j]=max(mx[i][j-],mx[f[i][j-]][j-]),f[i][j]=f[f[i][j-]][j-];
memset(ans,0x7f,sizeof(ans));
for(int i=;i<=m;i++)
if(!ty[i])
{
ans[a[i].pos]=query(a[i].x,a[i].y)-;
edge[++cnt].x=a[i].x;edge[cnt].y=a[i].y;edge[cnt].z=a[i].z;
}
sort(edge+,edge++cnt,cmp);
for(int i=;i<=n;i++)fa[i]=i;
for(int i=;i<=cnt;i++)
{
x=edge[i].x;y=edge[i].y;f1=gf(x);f2=gf(y);lastx=;lasty=;
while(f1!=f2)
{
if(d[f1]<d[f2])swap(x,y),swap(f1,f2),swap(lastx,lasty);
if(!v[x])
{
v[x]=i;
if(lastx)fa[lastx]=x;
}
else if(lastx)fa[lastx]=f1;
lastx=f1;x=f[f1][];f1=gf(x);
}
}
for(int i=;i<=m;i++)if(ty[i]&&v[d[a[i].x]>d[a[i].y]?a[i].x:a[i].y])ans[a[i].pos]=edge[v[d[a[i].x]>d[a[i].y]?a[i].x:a[i].y]].z-;
for(int i=;i<=m;i++)printf("%d ",ans[i]>=inf?-:ans[i]);
}

倍增+并查集: 

倍增:             

树链剖分:      

浴谷夏令营例题Codeforces827DBest Edge Weight(三个愿望,一次满足~(大雾的更多相关文章

  1. CF#633 D. Edge Weight Assignment

    D. Edge Weight Assignment 题意 给出一个n个节点的树,现在要为边赋权值,使得任意两个叶子节点之间的路径权值异或和为0,问最多,最少有多少个不同的权值. 题解 最大值: 两个叶 ...

  2. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

  3. CF 633 div1 1338 B. Edge Weight Assignment 构造

    LINK:Edge Weight Assignment 这场当时没打 看到这个B题吓到我了 还好当时没打. 想了20min才知道怎么做 而且还不能证明. 首先考虑求最小. 可以发现 如果任意两个叶子节 ...

  4. 【题解】洛谷P4281 [AHOI2008] 紧急集合(求三个点LCA)

    洛谷P4281:https://www.luogu.org/problemnew/show/P4281 思路 答案所在的点必定是三个人所在点之间路径上的一点 本蒟蒻一开始的想法是:先求出2个点之间的L ...

  5. Codeforces827D. Best Edge Weight

    $n \leq 2e5,m \leq 2e5$的有边权图,对每条边问:不改其他边的情况下这条边最多能是多少使得他一定在所有最小生成树上,如果无穷大输出-1. 典型题+耗时题,CF上的绝望时刻..打VP ...

  6. Codeforces 828F Best Edge Weight - 随机堆 - 树差分 - Kruskal - 倍增算法

    You are given a connected weighted graph with n vertices and m edges. The graph doesn't contain loop ...

  7. cf827D Best Edge Weight (kruskal+倍增lca+并查集)

    先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...

  8. 【比赛】洛谷夏令营NOIP模拟赛

    Day1 第一题 水题 第二题 题意:一个n*m的字符矩阵从左上到右下,经过字符形成回文串的路径数.n≤500 回文串,考虑两段往中间DP. f[k][x][y]表示走了k步,左上点横坐标为x,右下点 ...

  9. 洛谷 P4245 [模板]任意模数NTT —— 三模数NTT / 拆系数FFT(MTT)

    题目:https://www.luogu.org/problemnew/show/P4245 用三模数NTT做,需要注意时间和细节: 注意各种地方要取模!传入 upt() 里面的数一定要不超过2倍 m ...

随机推荐

  1. Python-S9——Day82-CRM项目实战

    1.权限的概念: 2.RBAC的设计: 3.注册登录用户所有权限到session中: 4.权限的校验: 5.基于中间件的权限校验: 1.权限的概念: 1.1 项目与应用: Project App 1. ...

  2. Linearize an sRGB texture in Photoshop

    From:https://forum.unity.com/threads/bug-with-bypass-srgb-sampling.282469/

  3. 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域

    此篇文章是对上一篇文章(http://www.ifiero.com/index.php/archives/611)的进一步补充,主要说明如何适配Apple的最新三款手机iPhoneXs.iPhoneX ...

  4. Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术

    第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...

  5. spark操作数据库的几种方法

    一.使用jdbcRDD的接口: SparkConf conf = new SparkConf(); conf.setAppName("Simple Application").se ...

  6. 【zabbix 监控】第一章 zabbix的安装配置

    安装前准备 一.下载网络yum源: http://mirrors.163.com/.help/centos.html https://opsx.alibaba.com/mirror 1.首先备份/et ...

  7. [2018 ACL Short and System] 对话系统

    Short Paper(s) 1.  Task-oriented Dialogue System for Automatic Diagnosis. (Cited by 0) Zhongyu Wei, ...

  8. Machine Learning笔记整理 ------ (三)基本性能度量

    1. 均方误差,错误率,精度 给定样例集 (Example set): D = {(x1, y1), (x2, y2), (x3, y3), ......, (xm, ym)} 其中xi是对应属性的值 ...

  9. HADOOP/HDFS Essay

    HDFS架构 the core of HADOOP/distributed systems is storeage(HDFS) and resource manager(YARN) for compu ...

  10. 软件工程 作业part3 读后感

    匆匆看完构建之法,觉得这种不认真看完书就去写随笔去评价这本书是对作者的不尊重,所以觉得应该提问题和写感悟. 我的一点拙见,提的问题在现在这个信息发达的时候感觉只要有时间都可以自己解决. 感觉软件工程这 ...