入门OJ:八中生成树2
题目描述
八中里面有N个建设物,M条边。对于这种要建最小生成树的问题,你应该很熟练了。现在老大决定降低某条边的费用,然后这条边必须要被选中,因为这条路他每天都要走,自然......问选了这条边后是否可以得到一个比从前总开支相等或更小的方案。
输入格式
第一行三个整数N,M,Q(1<=N<=1000,N-1<=M<=100000接下来M行,每行三个整数(X,Y,Z)描述一条可以建造的路。 0<=Z<=10000 最后Q行,每行两个整数i,x(1<=i<=M,0<=x)描述一个修改计划,即要你判断如果 将第i条公路的修建费用降低为x元后,是否可以得到一个比从前总开支相等或更小的方案
输出格式
按顺序输出Q行,每行输出"Yes"或"No",Yes表示可以建造,No表示不可能
先考虑暴力。
我们可以每次询问之后都修改一次边权,然后在原图求一次最小生成树,看是否更优即可。时间复杂度为O(Q * MlogM)
其实在原图再求一次mst时基本上所有边都是不需要变动的。可以利用这一点考虑优化
如果询问给出的边是树上边,那么只需比较和原来的树边大小即可。
如果不是树上边,那么如果原树不变,只加上询问的边,就会形成一个环。设询问给出的边为E(u,v),那么这个环就可以表示为:u->LCA(u,v)->v->u。所以生成树上唯一需要改变的就是这个环上的部分。只需要把环断掉一条边即可。为了使断掉之后的生成树尽可能小,我们肯定会断掉环上最长的边(除了询问给的边)。所以问题就变成了:求路径u->LCA(u,v)->v上最长边。
可以用倍增做,时间复杂度为O((N+M)logN),总复杂度就是:O((N+Q)logN+MlogM)。也可以树剖直接做,复杂度为O(QlogNlogN+MlogM)。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1001
#define maxm 100001
using namespace std;
struct brim{
int u,v,w;
bool operator<(const brim &b)const{ return w<b.w; }
}b[maxm],tmp[maxm];
struct edge{
int to,dis,next;
edge(){}
edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
}e[maxn<<1];
int head[maxn],k;
struct node{
int l,r,c;
}t[maxn<<2];
int anc[maxn];
int size[maxn],fa[maxn],son[maxn],dep[maxn];
int top[maxn],dfn[maxn],id[maxn],tot;
bool vis[maxn];
int n,m,q,val[maxn];
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void add(const int &u,const int &v,const int &w){
e[k]=edge(v,w,head[u]);
head[u]=k++;
}
int get(int x){ return anc[x]==x?x:anc[x]=get(anc[x]); }
inline int kruskal(){
for(register int i=1;i<=n;i++) anc[i]=i;
for(register int i=1;i<=m;i++) tmp[i]=b[i];
sort(tmp+1,tmp+1+m);
for(register int i=1;i<=m;i++){
int u=tmp[i].u,v=tmp[i].v,w=tmp[i].w;
if(get(u)==get(v)) continue;
anc[get(u)]=get(v),add(u,v,w),add(v,u,w);
}
}
void dfs_getson(int u){
size[u]=1;
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa[u]) continue;
dep[v]=dep[u]+1,fa[v]=u;
dfs_getson(v);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs_rewrite(int u,int tp){
top[u]=tp,dfn[u]=++tot,id[tot]=u;
if(son[u]) dfs_rewrite(son[u],tp);
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v!=son[u]&&v!=fa[u]) dfs_rewrite(v,v);
}
}
inline void endow(){
for(register int i=0;i<k;i+=2){
int u=e[i].to,v=e[i^1].to;
if(dep[u]>dep[v]) swap(u,v);
val[v]=e[i].dis;
}
}
void build(int d,int l,int r){
t[d].l=l,t[d].r=r;
if(l==r){ t[d].c=val[id[l]]; return; }
int mid=l+r>>1;
build(d<<1,l,mid),build(d<<1|1,mid+1,r);
t[d].c=max(t[d<<1].c,t[d<<1|1].c);
}
int getmax(int d,const int &l,const int &r){
if(l<=t[d].l&&t[d].r<=r) return t[d].c;
int mid=t[d].l+t[d].r>>1,ans=0;
if(l<=mid) ans=max(ans,getmax(d<<1,l,r));
if(r>mid) ans=max(ans,getmax(d<<1|1,l,r));
return ans;
}
int main(){
memset(head,-1,sizeof head);
n=read(),m=read(),q=read();
for(register int i=1;i<=m;i++) b[i].u=read(),b[i].v=read(),b[i].w=read();
kruskal();
dfs_getson(1);
dfs_rewrite(1,1);
endow();
build(1,1,tot);
for(register int i=1;i<=q;i++){
int id=read(),w=read(),mmax=0,u=b[id].u,v=b[id].v;
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]]) swap(u,v);
mmax=max(mmax,getmax(1,dfn[top[v]],dfn[v]));
v=fa[top[v]];
}
if(dep[u]>dep[v]) swap(u,v);
if(u!=v) mmax=max(mmax,getmax(1,dfn[u]+1,dfn[v]));
printf("%s\n",mmax-w>=0?"Yes":"No");
}
return 0;
}
入门OJ:八中生成树2的更多相关文章
- 【入门OJ】2003: [Noip模拟题]寻找羔羊
这里可以复制样例: 样例输入: agnusbgnus 样例输出: 6 这里是链接:[入门OJ]2003: [Noip模拟题]寻找羔羊 这里是题解: 题目是求子串个数,且要求简单去重. 对于一个例子(a ...
- 【大视野入门OJ】1099:歌德巴赫猜想
Description 歌德巴赫猜想大家都很熟悉吧?给一个数,能够分解成两个素数的和.现在要给你一个n,6 <= n < 1000000,让你求他会分解成哪两个素数?如果存在多组解,则要求 ...
- 【大视野入门OJ】1083:数组的二分查找
Description 在1500个整数中查整数x的位置,这些数已经从小到大排序了.若存在则输出其位置,若不存在则输出-1. Input 第一行,一个整数x 后面1500行,每行一个整数 Output ...
- 入门oj 6492: 小B的询问
Description 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L ...
- 入门oj 5499: 讲话模式
Description 每个人说话都有口头禅,现给出一个字符串,请求出其中出现次数最多的单词(不区分大小写). Input 输入一行,长度小于等于1048576的字符串输入至少包含一个字母或数字 Ou ...
- 入门oj 6451: The XOR Largest Pair之二
Description 今天小W用了1s不到的时候完成了这样一个题:在给定的N个整数 A_1,A_2,-,A_N中选出两个进行异或运算,得到的结果最大是多少?正当他志得意满时,L老师亮出了另一个题:给 ...
- 入门OJ:photo
题目描述 有N个人,来自K个家族.他们排成一行准备照相,但是由于天生的排外性,每个人都希望和本家族的人站在一起,中间不要加入别的家族的人.问最少从队列中去掉多少个就可以达到这个目的. 输入格式 第一行 ...
- 入门OJ:简单的网络游戏
题目描述 在某款极具技术含量的网络游戏中,佳佳靠着他的聪明智慧垄断了游戏中的油田系统.油田里有许多油井,这些油井排成一个M*N的矩形.每个油井都有一个固定的采油量.每两个相邻的油井之间有一条公路,这些 ...
- 入门OJ:Coin
题目描述 你有n个硬币,第i硬币面值为ai,现在总队长想知道如果丢掉了某个硬币,剩下的硬币能组成多少种价值?(0价值不算) 输入格式 第一行一个整数n 第二行n个整数.,a1,a2-an. 1< ...
随机推荐
- 测开之数据类型· 第3篇《列表推导式、字典推导式、2种方式创建生成器》
坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.列表推导式 二.字典推导式 三.2种方式创建生成器 1.生成器表达式 2.函数里面,通过 y ...
- Eureka系列(八)服务剔除具体实现
服务下线的大致流程图 下面这张图很简单地描述了服务剔除的大致流程: 服务剔除实现源码分析 首先我们得了解下服务剔除这个定时任务是什么被初始化启动的,在百度搜索中,在我们Eureka Serve ...
- iOS音乐电台类项目开发
1.技术难度不是太大,代码大致如下 2.用到的一些第三方 ZFProgressView,pageController,RESideMenu,MJRefresh,MBProgressHUD,RNFros ...
- 【命令】gunzip命令
gunzip命令是拿来解以.gz格式的压缩包,其语法和参数选项和gzip一样,我们可以使用gzip来实现,请查看:gzip命令使用方法
- JavaEE在职加薪课好客租房项目实战视频教程
JavaEE在职加薪课好客租房项目实战视频教程课程介绍: 本课程采用SOA架构思想进行设计,基于目前主流后端技术框架SpringBoot.SpringMVC.Mybaits.Dubbo等来 ...
- 【代码周边】Idea设置类注解和方法注解(带图)
Idea版本: 类注解 打开setting→Editor→Code Style→File and Code Templates /** * Created with IntelliJ IDEA. * ...
- Reset 对象属性
Input Reset 对象 在 HTML 表单中 标签每出现一次,一个 Reset 对象就会被创建. 当重置按钮被点击,包含它的表单中所有输入元素的值都重置为它们的默认值.默认值由 HTML val ...
- hadoop伪分布式平台组件搭建
第一部分:系统基础配置 系统基础配置中主完成了安装大数据环境之前的基础配置,如防火墙配置和安装MySQL.JDK安装等 第一步:关闭防火墙 Hadoop与其他组件的服务需要通过端口进行通信,防火墙的存 ...
- WebService 适用场合
适用场合 1.跨防火墙通信 如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题.因为客户端和服务器之间通常会有防火墙或者代理服 务器.在这种情况下,使用D ...
- 入门Kubernetes -基础概念
一.Kubernetes概述 Kubernetes ,又称为 k8s(首字母为 k.首字母与尾字母之间有 8 个字符.尾字母为 s,所以简称 k8s)或者简称为 "kube" ,是 ...