题目描述

  N个点M条边的无向图,每个点有一个初始颜色,每次改变一个点的颜色,求改变后整张图上颜色不同的点之间的距离最小值。

思路

考虑整张图的距离最小值一定是一条边,而不可能是一条路径,那么显然这条边一定在MST上,于是我们考虑怎样维护这棵MST。

  • 首先我们用kruskal建出MST,然后转化为有根树,把边权下放为点权,只维护每个点和它儿子的信息。
  • 我们对每个节点所有儿子的颜色开一个multiset,维护每个点的儿子中每种颜色对应的最小边权(此时下放为点权),为了节省空间我们用map映射把颜色那维去掉,即$CLS_{u,col}}
  • 接着我们再对每个点开一个multiset维护每个点儿子中所有颜色对应的最小边权的最小值(就是上一个multiset维护的东西的最小值)。即$best[u]=min\{CLS_{u,c} \}_{C \in all colors }$
  • 最后我们对全局开一棵线段树,维护每个点的best中和它颜色不同的点的最小值,便于修改和查询。
  • 于是每个点的答案不是$*best.begin()就是*(best.begin()+1)$,如果儿子中点权最小的儿子和父亲颜色相同,那么显然是次小的(或者无解)。
  • 怎样修改,考虑我们修改u时,先把$u$从父亲节点的信息中删去,再加回来。这里的方法是:先把$best$中对应的$col[u]$的信息删掉,然后把当前点所在的$cls[f[u]][col]$中找到并删去当前点,重新排序后再加入$best$中;接着把u的信息加入到$cls[f[u]][B]$(B为修改后颜色)中,同样先删去$best$中B的信息删掉,然后把u的信息加入$cls[f[u][B]$中,重新排序后再加入$best$中。
#include<bits/stdc++.h>
#define I inline
#define fi first
#define se second
#define mp make_pair
#define ls (now<<1)
#define rs (now<<1|1)
#define smid (l+r>>1)
using namespace std;
typedef map<int,multiset<int> >::iterator itcls;
//神仙typedef,这里是map的指针,it->fi是前面的集合,it->se是后面映射的集合
typedef set<pair<int,int> >::iterator itset;//it是一个pair型的东西
const int N=;
const int inf=;
I int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} struct EDGE
{
int u,v,w;
}e[N];
struct node
{
int to,nxt,w;
}g[N<<];
int head[N],cnt;
int n,m,k,q;
int col[N],w[N],f[N]; int mi[N<<];
I void pushup(int now){mi[now]=min(mi[ls],mi[rs]);} I void bt(int now,int l,int r)
{
mi[now]=inf;
if(l==r)return;
bt(ls,l,smid);bt(rs,smid+,r);
pushup(now);
} I void modify(int now,int l,int r,int pos,int val)
{
if(l==r){mi[now]=val;return;}
if(pos<=smid)modify(ls,l,smid,pos,val);
else modify(rs,smid+,r,pos,val);
pushup(now);
} I bool cmp(EDGE a,EDGE b){return a.w<b.w;} I void add(int u,int v,int w)
{
g[++cnt].nxt=head[u];
g[cnt].to=v;g[cnt].w=w;
head[u]=cnt;
} struct DSU
{
int f[N];
I void init(int x){for(int i=;i<=x;i++)f[i]=i;}
I int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
}dsu; I void kruskal()
{
sort(e+,e++m,cmp);
int tot=;cnt=;
dsu.init(n);
for(int i=;i<=m;i++)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
if(dsu.getf(u)!=dsu.getf(v))
{
dsu.f[dsu.getf(u)]=dsu.getf(v);
tot++;add(u,v,w);add(v,u,w);
if(tot==n-)return;
}
}
} map<int,multiset<int> >cls[N];
multiset<pair<int,int> >best[N]; I void dfs(int u,int fa)
{
f[u]=fa;
for(int i=head[u];i;i=g[i].nxt)
{
int v=g[i].to;
if(v==fa)continue;
w[v]=g[i].w;cls[u][col[v]].insert(w[v]);
dfs(v,u);
}
for(itcls it=cls[u].begin();it!=cls[u].end();it++)
best[u].insert(mp(*((it->se).begin()),it->fi));
//真·STL,(it维护的是map的指针,it->se是映射的multiset,it->fi是颜色
if(best[u].empty())return; itset it=best[u].begin();
if((it->se)!=col[u])modify(,,n,u,it->fi);
else
{
it++;if(it==best[u].end())modify(,,n,u,inf);
else modify(,,n,u,it->fi);
}
} int main()
{
n=read();m=read();k=read();q=read();
for(int i=;i<=m;i++)
{
int x=read(),y=read(),z=read();
e[++cnt]=(EDGE){x,y,z};
}
for(int i=;i<=n;i++)col[i]=read();
kruskal();bt(,,n);dfs(,);
while(q--)
{
int u=read(),c2=read();
if(f[u])
{
int c1=col[u];
best[f[u]].erase(best[f[u]].find(mp(*cls[f[u]][c1].begin(),c1)));
cls[f[u]][c1].erase(cls[f[u]][c1].find(w[u]));
if(cls[f[u]][c1].empty())cls[f[u]][c1].insert(inf);
best[f[u]].insert(mp(*cls[f[u]][c1].begin(),c1)); if(!cls[f[u]][c2].empty())
best[f[u]].erase(best[f[u]].find(mp(*cls[f[u]][c2].begin(),c2)));
cls[f[u]][c2].insert(w[u]);
best[f[u]].insert(mp(*cls[f[u]][c2].begin(),c2));
itset it=best[f[u]].begin();
if((it->se)!=col[f[u]])modify(,,n,f[u],it->fi);
else
{
it++;if(it==best[f[u]].end())modify(,,n,f[u],inf);
else modify(,,n,f[u],it->fi);
}
}
if(!best[u].empty())
{
itset it=best[u].begin();
if((it->se)!=c2)modify(,,n,u,it->fi);
else
{
it++;if(it==best[u].end())modify(,,n,u,inf);
else modify(,,n,u,it->fi);
}
}
col[u]=c2;
printf("%d\n",mi[]);
}
}

P3665 [USACO17OPEN]Switch Grass的更多相关文章

  1. Luogu 3665 [USACO17OPEN]Switch Grass 切换牧草

    BZOJ 4777 被权限了. 这道题的做法看上去不难,但是感觉自己yy不出来. 首先是两个结论: 1.答案一定是连接着两个异色点的一条边. 2.答案一定在最小生成树上. 感觉看到了之后都比较显然,自 ...

  2. BZOJ 4777: [Usaco2017 Open]Switch Grass

    4777: [Usaco2017 Open]Switch Grass Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 46  Solved: 10[Su ...

  3. BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树

    这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过Kruskal和一棵平衡树来解决,时间复杂度是O(n*l ...

  4. BZOJ4777 [Usaco2017 Open]Switch Grass[最小生成树+权值线段树套平衡树]

    标题解法是吓人的. 图上修改询问,不好用数据结构操作.尝试转化为树来维护.发现(不要问怎么发现的)最小生成树在这里比较行得通,因为最近异色点对一定是相邻的(很好想),所以只要看最短的一条两端连着异色点 ...

  5. [bzoj4777]Switch Grass

    结论:最短路径一定是单独的一条边且在最小生成树上,可以用反证法证明.那么求出最小生成树,对于每一个点建立一棵权值线段树,再对每一个权值线段树上的叶子节点开一个multiset,维护所有儿子中该种颜色的 ...

  6. USACO 2017 US Open

    只会做T1,FallDream T2 n^2暴力AC,太强啦. T1.Modern Art 题目大意:有一个n*n的矩阵,一开始都是0,你有n^2种颜色,编号1到n^2,每次可以选出一种颜色涂满一个子 ...

  7. 游戏编程算法与技巧 Game Programming Algorithms and Techniques (Sanjay Madhav 著)

    http://gamealgorithms.net 第1章 游戏编程概述 (已看) 第2章 2D图形 (已看) 第3章 游戏中的线性代数 (已看) 第4章 3D图形 (已看) 第5章 游戏输入 (已看 ...

  8. 洛谷P3668 [USACO17OPEN]Modern Art 2 现代艺术2

    P3668 [USACO17OPEN]Modern Art 2 现代艺术2 题目背景 小TY的同学HF也想创作艺术 HF只有一块长条状的画布(画条),所以每一次涂色只能涂上连续几个单位的颜料,同样新的 ...

  9. Partition:分区切换(Switch)

    在SQL Server中,对超级大表做数据归档,使用select和delete命令是十分耗费CPU时间和Disk空间的,SQL Server必须记录相应数量的事务日志,而使用switch操作归档分区表 ...

随机推荐

  1. mpvue 页面预加载,新增preLoad生命周期

    存在的必要性:mpvue开发微信小程序,在页面跳转到新页面的过程中会有200ms左右的延迟,这个200ms如果用来请求新页面的接口,那么跳转到新页面或许已经渲染好了页面. 就是两种方式: 1.新页面跳 ...

  2. Airport Express UVA - 11374

    In a small city called Iokh, a train service, Airport-Express, takes residents to the airport more q ...

  3. Python3_基础

    目录 数据类型 变量 数据类型的转换 算术操作符 输入 字符串常用方法 数据类型 我们先来看看三种常见的数据类型 字符串 str 在Python中,字符串一般都用引号引起来,不管是用单引号还是双引号都 ...

  4. [NOIp2013] luogu P1970 花匠

    scy居然开网了. 题目描述 你有一个序列 aaa,你需要保留尽量多的数,使得剩下的数满足以下条件中的一个: ∀x∈[2,n−1]∩N∗\forall x\in[2,n-1]∩\N^*∀x∈[2,n− ...

  5. How to Compute The Derivatives (如何求导数)(TBC)

    A video by 3Blue1Brown in Bilibili\text{A video by 3Blue1Brown in Bilibili}A video by 3Blue1Brown in ...

  6. [CODEVS3366] 矿石

    题目描述 Description 经历了千辛万苦,小J找到了N块矿石.这些矿石都有毒性,但只要将两块矿石放在一起,再分开即可解毒.但任一两块矿石都可以互相吸引.为了降低吸引力,小J将他们放入一个直径仅 ...

  7. 虚拟机Ubuntu系统无法连接网络解决方案

    宿主机连接wifi,虚拟机无法联网 查看是否有网络图标 操作一: sudo service network-manager stopsudo rm /var/lib/NetworkManager/Ne ...

  8. 《Java并发编程实战》读书笔记-第4章 对象的组合

    设计线程安全的类 三个基本要素: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问管理策略 实例封闭 将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容 ...

  9. 扩展阿里p3c实现自定义代码规范检查

     前段时间fastjson报出了漏洞,只要打开setAutoType特性就会存在风险,自己测试环境的一个项目被揪出来了-_-!.虽然改动很小,但就是觉得憋屈.fastjson还是挺好的,想着禁用的话太 ...

  10. pytest5-使用conftest.py实现多文件共享fixture

    一个测试工程下是可以有多个conftest.py的文件,一般在工程根目录放一个conftest.py起到全局作用.在不同的测试子目录也可以放conftest.py,作用范围只在该层级以及以下目录生效. ...