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 ...
随机推荐
- yii使用CFrom调用ajax失败的记录
在学习配置yii的CFrom的时候,发现怎么也不能让ajax生效,后来看文档后 ,终于发现了问题的所在. 问题配置文件如下 public function getUserConfig(){ retur ...
- CentOS快速搭建LAMP环境
LAMP -- Linux Apache MySQL PHP 在CentOS安装的顺序,我一般是Apache -> MySQL -> PHP 第一步.安装并配置Apache 1.使用yu ...
- 牛客想开了大赛2 A-【六】平面(切平面)
A-[六]平面 链接:https://ac.nowcoder.com/acm/contest/907/A?&headNav=acm来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限 ...
- Flask中的后端并发思考(以Mysql:too many connections为例)
之前写过一篇<CentOS 下部署Nginx+Gunicorn+Supervisor部署Flask项目>,最近对该工程的功能进行了完善,基本的功能单元测试也做了. 觉得也是时候进行一下压力 ...
- PHP 数字补零 固定位数补0
在处理订单编号的时候,需要固定位数的数字,比如需要固定四位数格式: 1->0001 56->0056 288->0288 1992->1992 可以使用php内置函数str_p ...
- Java Servlet图片上传至指定文件夹并显示图片
在学习Servlet过程中,针对图片上传做了一个Demo,实现的功能是:在a页面上传图片,点击提交后,将图片保存到服务器指定路径(D:/image):跳转到b页面,b页面读取展示绝对路径(D:/ima ...
- C# 线程同步计数存在的问题
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- JS 对象的操作方法
第一种: 变量名.style.属性: 第二种: 变量名.style[参数]
- Luogu P1155 双栈排序 图论?模拟吧。。
今天想做做图论,于是点开了这道题....(是二分图染色然而我没看出来) 四种操作及条件: 1. s1.push() 需满足 待push的元素小于栈顶 && { 若在原序列中,待push ...
- 洛谷1220(区间dp)
要点 处于什么位置的题常用一个套路就是搞完\([l,r]\)以后处于0(l)或1(r)的状态,即\(dp[i][j][0/1]\). 对于此题dp意义为已经搞完\([l,r]\)的时最小的已耗电能,转 ...