浴谷夏令营例题Codeforces827DBest Edge Weight(三个愿望,一次满足~(大雾
这题在浴谷夏令营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(三个愿望,一次满足~(大雾的更多相关文章
- CF#633 D. Edge Weight Assignment
D. Edge Weight Assignment 题意 给出一个n个节点的树,现在要为边赋权值,使得任意两个叶子节点之间的路径权值异或和为0,问最多,最少有多少个不同的权值. 题解 最大值: 两个叶 ...
- 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集
[题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...
- CF 633 div1 1338 B. Edge Weight Assignment 构造
LINK:Edge Weight Assignment 这场当时没打 看到这个B题吓到我了 还好当时没打. 想了20min才知道怎么做 而且还不能证明. 首先考虑求最小. 可以发现 如果任意两个叶子节 ...
- 【题解】洛谷P4281 [AHOI2008] 紧急集合(求三个点LCA)
洛谷P4281:https://www.luogu.org/problemnew/show/P4281 思路 答案所在的点必定是三个人所在点之间路径上的一点 本蒟蒻一开始的想法是:先求出2个点之间的L ...
- Codeforces827D. Best Edge Weight
$n \leq 2e5,m \leq 2e5$的有边权图,对每条边问:不改其他边的情况下这条边最多能是多少使得他一定在所有最小生成树上,如果无穷大输出-1. 典型题+耗时题,CF上的绝望时刻..打VP ...
- 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 ...
- cf827D Best Edge Weight (kruskal+倍增lca+并查集)
先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...
- 【比赛】洛谷夏令营NOIP模拟赛
Day1 第一题 水题 第二题 题意:一个n*m的字符矩阵从左上到右下,经过字符形成回文串的路径数.n≤500 回文串,考虑两段往中间DP. f[k][x][y]表示走了k步,左上点横坐标为x,右下点 ...
- 洛谷 P4245 [模板]任意模数NTT —— 三模数NTT / 拆系数FFT(MTT)
题目:https://www.luogu.org/problemnew/show/P4245 用三模数NTT做,需要注意时间和细节: 注意各种地方要取模!传入 upt() 里面的数一定要不超过2倍 m ...
随机推荐
- HTMLTestRunner.py(Python3)
"""A TestRunner for use with the Python unit testing framework. Itgenerates a HTML re ...
- 第一篇 Flask基础篇之(配置文件,路由系统,模板,请求响应,session&cookie)
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- 通过 Python_Faker 生成测试数据
通过 Python_Faker 生成测试数据 一.介绍 在软件需求.开发.测试过程中,有时候需要使用一些测试数据,针对这种情况,我们一般要么使用已有的系统数据,你不可能通过手工来生成(最傻的方法)可能 ...
- Git 新建文件并提交
1.创建一个readme.txt. cd /home/cyp/learngit touch readme.txt vim readme.txt 编写内容, wq 保存推出 2.提交步骤 2.1 gi ...
- Python 函数参数类型大全(非常全!!!)
Python 函数参数类型大全(非常全!!!) 1.在python编写程序里面具有函数文档,它的主要作用是为了让别人可以更好的理解你的函数,所以这是一个好习惯,访问函数文档的方式是: MyFuncti ...
- 爬虫2.1-scrapy框架-两种爬虫对比
目录 scrapy框架-两种爬虫对比和大概流程 1. 传统spider爬虫 2. crawl型爬虫 3. 循环页面请求 4. scrapy框架爬虫的大致流程 scrapy框架-两种爬虫对比和大概流程 ...
- [译] JavaScript核心指南(JavaScript Core) 【转】
本文转自:http://remember2015.info/blog/?p=141#scope-chain 零.索引 对象(An Object) 原型链(A Prototype Chain) 构造函数 ...
- Docker 镜像构建的时候,应该小心的坑
不要改文件 如果run了以后,你还需要进入到容器中,修改容器的配置,那么,这个容器是危险的.一旦容器无法启动,就再也改不了配置.那么你就需要删除和重新run这个容器,而配置要再改一遍.一个可用的镜像在 ...
- win10下搭建私链
首先要下载geth,下载地址:https://gethstore.blob.core.windows.net/builds/geth-windows-amd64-1.7.0-6c6c7b2a.exe ...
- Samba共享权限分配
案例推荐:http://www.cnblogs.com/mchina/archive/2012/12/18/2816717.html 本文不详细介绍全部参数,只介绍完成需求的一些参数. 需求: 1,账 ...