标题解法是吓人的。


图上修改询问,不好用数据结构操作。尝试转化为树来维护。发现(不要问怎么发现的)最小生成树在这里比较行得通,因为最近异色点对一定是相邻的(很好想),所以只要看最短的一条两端连着异色点的边,而分析一下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[最小生成树+权值线段树套平衡树]的更多相关文章

  1. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

  2. 【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree

    题目描述 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob ...

  3. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  4. bzoj4605: 崂山白花蛇草水 权值线段树套KDtree

    bzoj4605: 崂山白花蛇草水 链接 bzoj loj 思路 强制在线,那就权值线段树套KDtree好了,没啥好讲的. KDtree要加平衡因子来重构.另外,那水真难喝. 错误 树套树一边写过了, ...

  5. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  6. [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 ...

  7. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

  8. BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  9. 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...

随机推荐

  1. 如何限制nginx的响应速率

    参考官方地址:http://nginx.org/en/docs/http/ngx_http_core_module.html#variables 用$limit_rate内置的变量可以限制nginx的 ...

  2. Java中对JSONArray中的对象进行排序

    String jsonArrStr = "[ { \"ID\": \"135\", \"Name\": \"Fargo ...

  3. Go语言实例化结构体——为结构体分配内存并初始化

    转自: http://c.biancheng.net/view/66.html 结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存.因此必须在定义结构体并实例化后才能使用结构 ...

  4. GIL全局解释器

    ' GIL是一个互斥锁:保证数据的安全(以牺牲效率来换取数据的安全) 阻止同一个进程内多个线程同时执行(不能并行但是能够实现并发) 并发:看起来像同时进行的 GIL全局解释器存在的原因是因为CPyth ...

  5. log4j rootLogger配置示例(log4j.properties)

    log4j.rootLogger=INFO,commonLogger, log4j.appender.commonLogger=org.apache.log4j.ConsoleAppenderlog4 ...

  6. iview给布局MenuItem标签绑定点击事件

    @click.native="menuHandleClick"

  7. Spring实战(十一) 在Spring XML中配置AOP

    如果你没有源码,不能为通知类添加注解,又不想将AspectJ注解放入到你的代码中,必须选择XML配置了. 1.Spring XML配置文件 解析参考:http://www.cnblogs.com/bi ...

  8. Makefile速查笔记

    Makefile速查笔记 Makefile中的几个调试方法 一. 使用 info/warning/error 增加调试信息 a. $(info "some text")打印 &qu ...

  9. linux mysql-5.7.26 安装全记录

    买了个阿里云,自己折腾一下. 时间:2019年7月17日13:40:18 1.下载 wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7. ...

  10. .NET监视程序运行时间

    使用Stopwatch类(命名空间:System.Diagnostics;) 示例: using System; using System.Collections.Generic; using Sys ...