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 ...
随机推荐
- lua调用c函数
参考:http://blog.163.com/madahah@126/blog/static/170499225201121504936823/ 1.编辑C程序 vim luac.c #include ...
- Jdk 1.7*安装并配置
jdk 1.7的下载,见http://www.cnblogs.com/lchzls/p/6281448.html 新建JAVA_HOME指明JDK安装路径,就是刚才安装时所选择的路径C:\Progra ...
- IIS 上传大文件 30MB 设置限制了上传大小
用uploadify在IIS6下上传大文件没有问题,但是迁移到IIS7下面,上传大文件时,出现HTTP 404错误. 查了半天,原来是IIS7下的默认设置限制了上传大小.这个时候Web.Config中 ...
- laravel ajax提交登陆存储session,并输出
前端输出session {{ Session::get('username') }} ajax提交 <div>{{ Session::get('username') }}</div& ...
- codeforces757F Team Rocket Rises Again【支配树+倍增+拓扑+spfa】
先跑spfa求出最短路构成的DAG,然后在DAG上跑出支配树dfs出size取max即可 关于支配树,因为是DAG,支配点就是入点在支配树上的lca,所以一边拓扑一边预处理倍增,然后用倍增求lca # ...
- poj2241 The Tower of Babylon
The Tower of Babylon 题意:给你n种石头,长x,宽y,高z,每种石头数目无限,一块石头能放到另一块上的条件是:长和宽严格小于下面的石头.问叠起来的最大高度. /* 有些类似“叠箱子 ...
- [Xcode 实际操作]七、文件与数据-(5 )复制、移动、删除文件和删除文件夹
目录:[Swift]Xcode实际操作 本文将演示如何复制.移动和删除文件. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class ...
- C 语言实例 - 循环输出26个字母
C 语言实例 - 循环输出26个字母 循环输出 个字母. 实例 #include <stdio.h> int main() { char c; for(c = 'A'; c <= ' ...
- LeetCode 刷题笔记 (树)
1. minimum-depth-of-binary-tree 题目描述 Given a binary tree, find its minimum depth.The minimum depth ...
- 042 Trapping Rain Water 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算下雨之后能接多少雨水.例如,输入 [0,1,0,2,1,0,1,3,2,1,2,1],返回 6. 详见:https://leetcode.c ...