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 ...
随机推荐
- c 无回显读取字符/不按回车即获取字符
最近课程设计要使用各种有趣的函数,这是其中一个 #include <conio.h> 使用方法 char c; c=getch(); 这样按下输入一个字符不按回车就ok了
- font-size: 0;解决元素间的空白间隙
看别人的代码看到过font-size:0这个设置,不明白为何这样操作,后来研究一下才明白:这是像素级还原设计稿很有用的设置,因为元素节点有文本节点,在缩进代码时会占据宽度,这么说不好理解,演示如下: ...
- 基于Laravel框架的一个简单易学的微信商城(新手必学)
俗话说,麻雀虽小可五脏俱全呀! 今天分享的这个基于Laravel的小项目大概功能有这些: 1.实现会员登录.注册功能.数据双向验证功能.2.实现手机短信验证.邮件激活账号.邮件通知.3.ajax提交数 ...
- [翻译]Nativescript 中 Web 视图与 Android/IOS 的双向通信
English document From http://shripalsoni.com/blog/nativescript-webview-native-bi-directional-communi ...
- LightOJ - 1234 LightOJ - 1245 Harmonic Number(欧拉系数+调和级数)
Harmonic Number In mathematics, the nth harmonic number is the sum of the reciprocals of the first n ...
- 移动构造和移动赋值与std::move
------------------------------------移动构造------------------------------------------ 传统的深拷贝深赋值 对于类中,含有 ...
- 【Java面试题系列】:Java基础知识常见面试题汇总 第二篇
文中面试题从茫茫网海中精心筛选,如有错误,欢迎指正! 第一篇链接:[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 1.JDK,JRE,JVM三者之间的联系和区别 你是否考虑过我们写的x ...
- Git入门 时光穿梭鸡 版本回退 工作区 暂存区
分布式集中式 CVS及SVN都是集中式的版本控制系统 , 而Git是分布式版本控制系统 集中式版本控制系统,版本库是集中存放在中央服务器的, 而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得 ...
- Unity中的Lod
http://blog.csdn.net/bigpaolee/article/details/48521371 LOD是( Level of Detail)的缩写,表示细节级别. 这里注意下,Lodg ...
- 洛谷P1633 二进制
P1633 二进制 题目描述 有三个整数A.B.C,以下用N(2)表示N的二进制(没有前导0). 设A(2).B(2).C(2)的最大长度为L,你需要构造三个正整数X.Y.Z,满足以下条件: (1) ...