这题在浴谷夏令营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. JS原型链与继承别再被问倒了

    原文:详解JS原型链与继承 摘自JavaScript高级程序设计: 继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式: 接口继承 和 实现继承 .接口继承只继承方法签名,而实 ...

  2. lintcode112 删除排序链表中的重复元素

    删除排序链表中的重复元素   给定一个排序链表,删除所有重复的元素每个元素只留下一个. 您在真实的面试中是否遇到过这个题? Yes 样例 给出 1->1->2->null,返回 1- ...

  3. 剑指offer-二叉搜索树的后序遍历序列23

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. class Solution: def Verif ...

  4. Ubuntu16.04安装truffle时的一些错误

    1.使用truffle时出现 Error: /usr/bin/env: node: 没有那个文件或目录 1.如果是用sudo apt-get install nodejs命令安装的nodejs, ub ...

  5. jdk1.8新特性-Lambda表达式使用要点

    前言 在jdk1.8出来的时候看到过,没怎么了解.但是最近再看kafka和spark框架,框架示例中ava版的很多地方用到Lambda表达式,发现使用Lambda表达式代码确实简单了好多,有些例子大致 ...

  6. 3.azkaban3.0测试

    测试目标 azkaban多executor下flow的分配方式 azkaban可以同时执行的flow\job个数 azkaban单个job最小使用的内存 相关配置 executor最大线程数: exe ...

  7. vue.js学习之 如何在手机上查看vue-cli构建的项目

    vue.js学习之 如何在手机上查看vue-cli构建的项目 一:找到config文件夹下的index.js文件,打开后,将host的值改为你本地的ip,保存后重启项目 二:输入ip和端口号打开项目 ...

  8. 冲刺ing-1

    冲刺一 1.第一天的工作分配: 姓名 任务分工 吴伟华(队长) 布置团队任务,发表汇总博客及第一次冲刺博客 蔺皓雯 讨论任务分配 杨池宇 讨论任务分配 鲁婧楠 讨论任务分配 曾茜 讨论任务分配 蔡晨旸 ...

  9. keydown事件下调用trigger事件执行两次

    $('button[type=button]').on('click',login); //登录 $(document).keydown(function(event){ if(event.keyCo ...

  10. iOS开发应用程序更新

    #import "ViewController.h" //1一定要先配置自己项目在商店的APPID,配置完最好在真机上运行才能看到完全效果哦 #define STOREAPPID ...