BZOJ 4777: [Usaco2017 Open]Switch Grass
4777: [Usaco2017 Open]Switch Grass
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 46 Solved: 10
[Submit][Status][Discuss]
题目:给定一张带权无向图,每个点有一个颜色,每次改变一个点的颜色,要求你在操作后输出这个图中最近异色点对之间的距离最近异色点对定义为:一对点颜色不同,且距离最小。
数据范围:N个点,M条无向边,Q次修改,颜色范围[1,k],边权L。N,M,Q≤200000,K≤N,1≤L≤106 .
想法:
发现1:答案肯定是某一边权。因为边权大于0,答案路径上肯定是先经过若干个相同颜色的点,最后再碰到不相同。所以只要取这条路径的末端两个点就好了....
发现2:对于原图的答案等价于其最小生成树图的答案。因为在一个环上,最大边权只可能变劣(画图看看嘛),满足最小生成树环切性。
所以问题变成了:给你一棵最小生成树,询问该时刻相邻异色点距离最小是多少。
在线搞:既然是棵树,每个节点用堆/set存下每个颜色中其儿子节点的距离。剩下好像就很明了....
离线搞:考虑一条边什么时候会作为答案。按边权从小到大考虑每条边,用并查集跳过已经有边的时间。用双向链表维护一个点的颜色时间段。
复杂度:O(n+q+mlogm) 如果用基数排序也许是线性算法?
#include<cstdio>
#include<vector>
#include<algorithm> const int len();
struct Data{int last,col,pre,suc;}look_v,look_u,look;
std::vector<Data>Seg[len+];
struct ABC{int a,b,c;bool bf;}L[len+];
struct Node{int nd,nx;}bot[len*+];
int tot,first[len+],depth[len+];
int f[len+],ans[len+];
int n,m,k,q,x,y,col[len+],last[len+];
template <class T>void read(T &x)
{
x=;bool f=;char c=getchar();
while((c<''||c>'')&&c!='-')c=getchar(); if(c=='-')f=,c=getchar();
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
x=f?-x:x;
}
template <class T>T abs(T x){return x<?-x:x;}
template <class T>T min(T a,T b){return a>b?b:a;}
void swap(int &x,int &y){x^=y,y^=x,x^=y;}
bool cmp(ABC A,ABC B){return A.c<B.c;}
void add(int a,int b){bot[++tot]=(Node){b,first[a]};first[a]=tot;}
int gf(int x)
{
int v=x;while(f[v]!=v)v=f[v];
for(int o;x!=v;x=o)o=f[x],f[x]=v;
return v;
}
void Kruskal()
{
for(int i=,fa,fb;i<=m;i++)
{
fa=gf(L[i].a); fb=gf(L[i].b);
if(fa!=fb)
{
f[fa]=fb;
L[i].bf=true;
}
}
}
void union_Seg(int x,int v)
{
int pre=Seg[x][v].pre,suc=Seg[x][v].suc,t=gf(Seg[x][v].last);
look=Seg[x][v];
if(Seg[x][suc].last<=t)//中间这块不会再被访问到
{
Seg[x][pre].suc=suc;
Seg[x][suc].pre=pre;
if(Seg[x][pre].col==Seg[x][suc].col)
{
Seg[x][pre].suc=Seg[x][suc].suc;//合并颜色相同的
Seg[x][Seg[x][pre].suc].pre=pre;
}
}
}
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
read(n),read(m),read(k),read(q);
for(int i=;i<=m;i++) read(L[i].a),read(L[i].b),read(L[i].c);
for(int i=;i<=n;i++) read(col[i]),f[i]=i,last[i]=;//从零开始
std::sort(L+,L++m,cmp);
Kruskal();
for(int i=,sz;i<=q;i++)
{
read(x),read(y);
sz=Seg[x].size();
Seg[x].push_back((Data){last[x],col[x],sz-,sz+});
col[x]=y; last[x]=i; f[i]=i;
}
for(int i=,sz;i<=n;i++)
{
sz=Seg[i].size();
Seg[i].push_back((Data){last[i],col[i],sz-,sz+});
Seg[i].push_back((Data){q+,,,});//边界
}
f[q+]=q+;
for(int i=;i<=m;i++)
if(L[i].bf)
{
x=L[i].a,y=L[i].b;
for(int now=,v=,u=;now<=q;)
{
now=gf(now+); if(now>q)break;
look=Seg[x][v];
for(int suc=Seg[x][v].suc;Seg[x][suc].last<=now;)
look=Seg[x][suc],v=suc,suc=Seg[x][suc].suc;//可以被卡到O(q^2)
look=Seg[y][u];
for(int suc=Seg[y][u].suc;Seg[y][suc].last<=now;)
look=Seg[y][suc],u=suc,suc=Seg[y][suc].suc;//可以被卡到O(q^2)
look_v=Seg[x][v]; look_u=Seg[y][u];
if(Seg[x][v].col!=Seg[y][u].col)ans[now]=L[i].c,f[now]=now+;//共O(n)
else now=min(Seg[x][ Seg[x][v].suc ].last,Seg[y][ Seg[y][u].suc ].last)-;//可以被卡到O(q^2)
union_Seg(x,v); union_Seg(y,u);//合并 简化 以保证不被卡成O(q^2)
//合并后 v,u不变没影响
}
}
for(int i=;i<=q;i++)printf("%d %d\n",i,ans[i]);
return ;
}
BZOJ 4777: [Usaco2017 Open]Switch Grass的更多相关文章
- BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树
这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过Kruskal和一棵平衡树来解决,时间复杂度是O(n*l ...
- BZOJ4777 [Usaco2017 Open]Switch Grass[最小生成树+权值线段树套平衡树]
标题解法是吓人的. 图上修改询问,不好用数据结构操作.尝试转化为树来维护.发现(不要问怎么发现的)最小生成树在这里比较行得通,因为最近异色点对一定是相邻的(很好想),所以只要看最短的一条两端连着异色点 ...
- Luogu 3665 [USACO17OPEN]Switch Grass 切换牧草
BZOJ 4777 被权限了. 这道题的做法看上去不难,但是感觉自己yy不出来. 首先是两个结论: 1.答案一定是连接着两个异色点的一条边. 2.答案一定在最小生成树上. 感觉看到了之后都比较显然,自 ...
- bzoj 4780: [Usaco2017 Open]Modern Art 2
4780: [Usaco2017 Open]Modern Art 2 Time Limit: 10 Sec Memory Limit: 128 MB Description Having becom ...
- 洛谷—— P3119 [USACO15JAN]草鉴定Grass Cownoisseur || BZOJ——T 3887: [Usaco2015 Jan]Grass Cownoisseur
http://www.lydsy.com/JudgeOnline/problem.php?id=3887|| https://www.luogu.org/problem/show?pid=3119 D ...
- 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...
- BZOJ 4756 [Usaco2017 Jan]Promotion Counting(线段树合并)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4756 [题目大意] 给出一棵树,对于每个节点,求其子树中比父节点大的点个数 [题解] ...
- bzoj 4756 [Usaco2017 Jan]Promotion Counting——线段树合并
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756 线段树合并裸题.那种返回 int 的与传引用的 merge 都能过.不知别的题是不是这 ...
- bzoj 4991 [Usaco2017 Feb]Why Did the Cow Cross the Road III(cdq分治,树状数组)
题目描述 Farmer John is continuing to ponder the issue of cows crossing the road through his farm, intro ...
随机推荐
- 微软企业库的 注入和依赖&nbs…
Working with ObjectBuilder This topic has not yet been rated - Rate this topic Retired Content This ...
- Fluuter常遇到的问题
The ADB binary found at XX is obsolete and has seriousperformance problems with the Android Emulator ...
- Python 数据分析:让你像写 Sql 语句一样,使用 Pandas 做数据分析
Python 数据分析:让你像写 Sql 语句一样,使用 Pandas 做数据分析 一.加载数据 import pandas as pd import numpy as np url = ('http ...
- hostent结构体和wsadata结构体
一.hostent结构体 使用这个东西,首先要包含2个头文件:#include <netdb.h>#include <sys/socket.h> struct hostent ...
- sqlserver2012——逻辑运算符
ALL 如果一组的比较都为TRUE,则结果为true ANY如果玉足比较中任何一个为true,则结果为true AND 两个boll都为TRUE,则结果为TRUE OR 两个BOLL任何一个TRUE, ...
- vim配置----YouCompleteMe配置
YouCompleteMe是一个功能极强的自动补全插件,安装这个插件折磨了我好久,找了很多博客查看都无果,最后还是感谢stack overflow.和其它的一些插件相比,YCM能够基于语法来给出相应的 ...
- 数据库路由中间件MyCat - 源代码篇(1)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...
- SmartSql使用教程(2)——使用动态代理实现CURD
一.引言 接着上一篇的教程,本章我们继续讲SmartSql.今天的主题是动态仓储. 老规矩,先上一个项目结构 从第二章开始.我们将原来的单一项目做了一个分离.方便之后的更新. 在这个结构中.原本上一章 ...
- static_cast、dynamic_cast、const_cast和reinterpret_cast总结
转自:http://www.jellythink.com/archives/205 前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中确实经常使用的. ...
- poj1191(記憶化搜索)
題目鏈接:http://poj.org/problem?id=1191 題意:中文題誒- 思路:這道題有幾個關鍵點需要想通,不然會比較難做... 首先,題目給出的標準差公式並不是很好計算,需要給它變下 ...