BZOJ4777 [Usaco2017 Open]Switch Grass[最小生成树+权值线段树套平衡树]
标题解法是吓人的。
图上修改询问,不好用数据结构操作。尝试转化为树来维护。发现(不要问怎么发现的)最小生成树在这里比较行得通,因为最近异色点对一定是相邻的(很好想),所以只要看最短的一条两端连着异色点的边,而分析一下kruskal的过程,发现满足这种要求的最小边一定会被加进去(因为相邻异色点总要联通),所以不管颜色怎么修改,答案一定在最小生成树上。于是,问题转化为了一棵树。`````
修改一个点的颜色,不妨只关心他和他儿子之间的所有边。由于要查询和自己颜色不同的儿子的最小权值,与颜色有关,所以可以对于每个点,开一个动态开点的以颜色为权值的线段树维护最小边权,这样可以直接把儿子插进去,查颜色$[1,color_x)\cup(color_x,k]$的最小值,这样$color_x$变化也可以快速查询啦。但是,由于原来的颜色没有了,所以要把自己原来的颜色从父亲对应的树上删掉,为了保证其他相同颜色的权值不会被影响,所以线段树每个叶子要开一个平衡树(这里用了multiset),来维护相同颜色的各种权值,然后删除这个点就行了,然后再再把新的颜色插入到父亲里。对于每个点,到儿子的最小异色点距离如果是$f_x$,那么每次修改,父亲和自己的$f_x$会变动,求全局$f$只要在开一个multiset就好了。
空间问题:初始每个点会被父亲插入一次,插入multiset一次,总的被插入$n$个点,之后的每次修改,每次父亲插入新的颜色一次,插入新的multiset一次,空间量级$O((n+q)\log n+(n+q))$。
时间:$O((n+q)\log^2 n)$。
Note:细节注意。
Note:BZOJ跑的比较卡内存,所以把内存开小了一点才贴着上限过的。下面的code没改小。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=2e5+,INF=0x3f3f3f3f;
struct tree_edge{int nxt,to,w;}G[N<<];
struct edge{
int u,v,w;
inline bool operator <(const edge&A)const{return w<A.w;}
}e[N];
int Head[N],tot;
int n,m,k,q;
inline void Addedge(int x,int y,int z){
G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;
G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z;
}
int anc[N];
inline int get_anc(int x){return anc[x]==x?x:anc[x]=get_anc(anc[x]);}
inline void Kruskal(){
sort(e+,e+m+);
for(register int i=;i<=n;++i)anc[i]=i;
for(register int i=;i<=m;++i)if(get_anc(e[i].u)^get_anc(e[i].v))anc[anc[e[i].u]]=anc[e[i].v],Addedge(e[i].u,e[i].v,e[i].w);
} struct segment_tree{
int lc[N*],rc[N*],minv[N*],pos[N*],cnt,mt;
multiset<int> s[N<<];
segment_tree(){memset(minv,0x3f,sizeof minv);}
inline void pushup(int i){minv[i]=_min(minv[lc[i]],minv[rc[i]]);}
void Insert(int&i,int L,int R,int c,int w){
if(!i)i=++cnt;
if(L==R){
if(!pos[i])pos[i]=++mt;
s[pos[i]].insert(w);minv[i]=*s[pos[i]].begin();
return;
}
int mid=L+R>>;
if(c<=mid)Insert(lc[i],L,mid,c,w);
else Insert(rc[i],mid+,R,c,w);
pushup(i);
}
int Query_min(int i,int L,int R,int ql,int qr){
if(ql<=L&&qr>=R)return minv[i];
int mid=L+R>>,ret=INF;
if(ql<=mid)MIN(ret,Query_min(lc[i],L,mid,ql,qr));
if(qr>mid)MIN(ret,Query_min(rc[i],mid+,R,ql,qr));
return ret;
}
void Delete(int i,int L,int R,int c,int w){
if(L==R){
s[pos[i]].erase(s[pos[i]].find(w));
minv[i]=s[pos[i]].empty()?INF:*s[pos[i]].begin();
return;
}
int mid=L+R>>;
if(c<=mid)Delete(lc[i],L,mid,c,w);
else Delete(rc[i],mid+,R,c,w);
pushup(i);
}
}T; int minv[N],fa[N],wt[N],val[N],rt[N];
multiset<int> ans;
#define y G[j].to
void dfs(int x,int fat){
fa[x]=fat;
for(register int j=Head[x];j;j=G[j].nxt)if(y^fat)dfs(y,x),T.Insert(rt[x],,k,val[y],wt[y]=G[j].w);
if(rt[x])minv[x]=_min(val[x]>?T.Query_min(rt[x],,k,,val[x]-):INF,val[x]<k?T.Query_min(rt[x],,k,val[x]+,k):INF),ans.insert(minv[x]);
}
#undef y
inline void change_father(int x,int c){
if(!fa[x])return;
T.Delete(rt[fa[x]],,k,val[x],wt[x]);//dbg("delete ok");
T.Insert(rt[fa[x]],,k,c,wt[x]);//dbg("insert ok");
ans.erase(ans.find(minv[fa[x]]));
ans.insert(minv[fa[x]]=_min(val[fa[x]]>?T.Query_min(rt[fa[x]],,k,,val[fa[x]]-):INF,val[fa[x]]<k?T.Query_min(rt[fa[x]],,k,val[fa[x]]+,k):INF));
// dbg2("new father",minv[fa[x]]);
}
inline void change_self(int x,int c){
if(!rt[x])return;
ans.erase(ans.find(minv[x]));
ans.insert(minv[x]=_min(val[x]>?T.Query_min(rt[x],,k,,val[x]-):INF,val[x]<k?T.Query_min(rt[x],,k,val[x]+,k):INF));
// dbg2("new self",minv[x]);
}
inline void Query(){
int x,c;
while(q--){
read(x),read(c);
change_father(x,c);
val[x]=c;
change_self(x,c);
printf("%d\n",*ans.begin());
}
}
inline void Init(){
read(n),read(m),read(k),read(q);
for(register int i=;i<=m;++i)read(e[i].u),read(e[i].v),read(e[i].w);
for(register int i=;i<=n;++i)read(val[i]);
} int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
Init();
Kruskal();
dfs(,);
Query();
return ;
}
总结:图上的操作题如果觉得维护困难可以尝试转化成树上问题,这时不妨就看看MST可不可以。
BZOJ4777 [Usaco2017 Open]Switch Grass[最小生成树+权值线段树套平衡树]的更多相关文章
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- 【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree
题目描述 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- bzoj4605: 崂山白花蛇草水 权值线段树套KDtree
bzoj4605: 崂山白花蛇草水 链接 bzoj loj 思路 强制在线,那就权值线段树套KDtree好了,没啥好讲的. KDtree要加平衡因子来重构.另外,那水真难喝. 错误 树套树一边写过了, ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- [BZOJ5139][Usaco2017 Dec]Greedy Gift Takers 权值线段树
Description Farmer John's nemesis, Farmer Nhoj, has NN cows (1≤N≤10^5), conveniently numbered 1…N. T ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
随机推荐
- PHP学习(2)——操作符与迭代整理
目录: 10.操作符整理 11.表单计算代码 12.优先级与结合性 13.可变函数 14.条件判断 15.循环迭代 16.跳出控制 17.可替换的控制结构 10.操作符 10.1 算术操作符 算术操作 ...
- BZOJ 2631 tree | Luogu P1501 [国家集训队]Tree II (LCT 多重标记下放)
链接:https://www.luogu.org/problemnew/show/P1501 题面: 题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: ...
- 【Python】【demo实验9】【练习实例】【三数排序】
原题: 输入三个整数x,y,z,请把这三个数由小到大输出. 我的解法: #!/usr/bin/python # encoding=utf-8 # -*- coding: UTF-8 -*- # 输入三 ...
- ABP领域层定义仓储并实现
原文作者:圣杰 原文地址:ABP入门系列(3)——领域层定义仓储并实现 在原文作者上进行改正,适配ABP新版本.内容相同 一.先来介绍下仓储 仓储(Repository): 仓储用来操作数据库进行数据 ...
- PAT B1011 A+B 和 C (15)
AC代码 #include <cstdio> int main() { int T, tcase = 1; scanf("%d", &T); for(int i ...
- Linux操作系统文档
一 Linux操作系统概述 l为什么要学习Linux操作系统: 1. 大部分服务端都是使用Linux操作系统(Django,爬虫,科学运算等项目是部署到服务器中的) 2. 一些企业和学校(国外学校 ...
- 关于Python中的lambda
lambda是Python编程语言中使用频率较高的一个关键字.那么,什么是lambda?它有哪些用法?网上的文章汗牛充栋,可是把这个讲透的文章却不多.这里,我们通过阅读各方资料,总结了关于Python ...
- T100——不绑定数据表字段,做查询条件(待改进)
此例子使用的方法有待改善,不是很好的方法. 范例:aimm200: 作用:查询时默认不显示无效料件:新增参数控制查询是否显示无效料件.(只作用查询,不影响新增.修改等)
- CSS和DOM入门
CSS补充: - position - background - hover - overflow - z-index - opacity 示例:输入框右边放置图标 JavaScript: 局部变量 ...
- Neo4j图数据库配置文件详解
For more details and a complete list of settings, please see https://neo4j.com/docs/operations-manua ...