这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过Kruskal和一棵平衡树来解决,时间复杂度是O(n*logn)级别的但是那个大常数..........然后在最外面独立一棵权值线段树来存最终答案.....

证明:若答案不是一条边,那么在这个答案里一定有中间点可以推翻答案;若答案不是在最小生成树内,那么在最小生成树上一定用答案可以更新他(这个答案边与最小生成树内这两个点的路径形成回路,那么他一定会被推翻)(最小生成树外的边与最小生成树形成回路,那个路径一定比回路内其它边大(或等),会被其它边替代)

一定要注意当查询时替罪羊的中间点可以生效时当且仅当,他在区间内并且他存在。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<queue>
  5. #include<algorithm>
  6. #define MAXN 200005
  7. #define Inf 1000000
  8. using namespace std;
  9. double alpha=0.756;
  10. inline int read()
  11. {
  12. int sum=;
  13. char ch=getchar();
  14. while(ch<''||ch>'')ch=getchar();
  15. while(ch>=''&&ch<='')
  16. {
  17. sum=(sum<<)+(sum<<)+ch-;
  18. ch=getchar();
  19. }
  20. return sum;
  21. }
  22. int sz;
  23. struct Seg_Tree
  24. {
  25. Seg_Tree *ch[];
  26. int l,r,mid,size;
  27. }node[Inf<<],*seg;
  28. inline Seg_Tree *New(int l,int r)
  29. {
  30. Seg_Tree *p=&node[++sz];
  31. p->l=l;
  32. p->r=r;
  33. p->mid=(l+r)>>;
  34. p->size=;
  35. return p;
  36. }
  37. inline int Min(int x,int y)
  38. {
  39. return x<y?x:y;
  40. }
  41. struct ScapeGoat_Tree
  42. {
  43. ScapeGoat_Tree *ch[],*f;
  44. int key,size,col,ex,cover,min;
  45. void pushup()
  46. {
  47. size=ch[]->size+ex+ch[]->size;
  48. cover=ch[]->cover++ch[]->cover;
  49. min=Min(ch[]->min,ch[]->min);
  50. if(ex)min=Min(key,min);
  51. }
  52. bool bad()
  53. {
  54. return cover*alpha+<ch[]->cover||cover*alpha+<ch[]->size;
  55. }
  56. }mempool[MAXN<<],*list[MAXN<<],*stack[MAXN<<],*null,*root[MAXN],*pos[MAXN];
  57. int len,top;
  58. inline void pre()
  59. {
  60. null=mempool;
  61. for(int i=;i<(MAXN<<);i++)stack[++top]=mempool+i;
  62. null->ch[]=null->ch[]=null->f=null;
  63. null->key=null->min=0x7fffffff;
  64. for(int i=;i<MAXN;i++)root[i]=null;
  65. }
  66. inline ScapeGoat_Tree *New(int key,ScapeGoat_Tree *fa,int co)
  67. {
  68. ScapeGoat_Tree *p=stack[top--];
  69. p->ch[]=p->ch[]=null;
  70. p->min=p->key=key;
  71. p->f=fa;
  72. p->col=co;
  73. p->size=p->cover=p->ex=;
  74. return p;
  75. }
  76. struct Tr
  77. {
  78. int to,next,w;
  79. }C[MAXN<<];
  80. int Head[MAXN],T;
  81. inline void Add(int x,int y,int z)
  82. {
  83. C[++T].to=y;
  84. C[T].next=Head[x];
  85. Head[x]=T;
  86. C[T].w=z;
  87. }
  88. int col[MAXN],Ans[MAXN];
  89. struct E
  90. {
  91. int x,y,z;
  92. }e[MAXN];
  93. int n,m,k,q;
  94. int Fa[MAXN];
  95. int comp(const E a,const E b)
  96. {
  97. return a.z<b.z;
  98. }
  99. int f[MAXN];
  100. int find(int x)
  101. {
  102. return Fa[x]==x?x:(Fa[x]=find(Fa[x]));
  103. }
  104. inline void unit(int x,int y)
  105. {
  106. if(x!=y)Fa[x]=y;
  107. }
  108. inline void Kruskal()
  109. {
  110. sort(e+,e+m+,comp);
  111. for(int i=;i<=n;i++)
  112. Fa[i]=i;
  113. int had=;
  114. for(int i=;i<=m;i++)
  115. if(find(e[i].x)!=find(e[i].y))
  116. {
  117. Add(e[i].x,e[i].y,e[i].z);
  118. Add(e[i].y,e[i].x,e[i].z);
  119. unit(find(e[i].x),find(e[i].y));
  120. had++;
  121. if(had==n)break;
  122. }
  123. }
  124. ScapeGoat_Tree **insert(int key,int co,ScapeGoat_Tree *&p,int id,ScapeGoat_Tree *fa)
  125. {
  126. if(p==null)
  127. {
  128. p=New(key,fa,co);
  129. pos[id]=p;
  130. return &null;
  131. }
  132. ScapeGoat_Tree **ret=insert(key,co,p->ch[p->col<=co],id,p);
  133. if(p->bad())ret=&p;
  134. p->pushup();
  135. return ret;
  136. }
  137. void travel(ScapeGoat_Tree *p)
  138. {
  139. if(p==null)return;
  140. travel(p->ch[]);
  141. if(p->ex)list[++len]=p;
  142. else stack[++top]=p;
  143. travel(p->ch[]);
  144. }
  145. ScapeGoat_Tree *divide(int l,int r,ScapeGoat_Tree *fa)
  146. {
  147. if(l>r)return null;
  148. int mid=(l+r)>>;
  149. list[mid]->ch[]=divide(l,mid-,list[mid]);
  150. list[mid]->ch[]=divide(mid+,r,list[mid]);
  151. list[mid]->f=fa;
  152. list[mid]->pushup();
  153. return list[mid];
  154. }
  155. inline void rebuild(ScapeGoat_Tree *&p)
  156. {
  157. len=;
  158. ScapeGoat_Tree *fa=p->f;
  159. travel(p);
  160. p=divide(,len,fa);
  161. }
  162. inline void Insert(int key,int co,ScapeGoat_Tree *&Root,int id)
  163. {
  164. ScapeGoat_Tree **p=insert(key,co,Root,id,null);
  165. if(*p!=null)rebuild(*p);
  166. }
  167. void dfs(int x)
  168. {
  169. for(int i=Head[x];i;i=C[i].next)
  170. if(C[i].to!=f[x])
  171. {
  172. f[C[i].to]=x;
  173. Insert(C[i].w,col[C[i].to],root[x],C[i].to);
  174. dfs(C[i].to);
  175. }
  176. }
  177. void build(Seg_Tree *p)
  178. {
  179. if(p->l==p->r)return;
  180. p->ch[]=New(p->l,p->mid);
  181. p->ch[]=New(p->mid+,p->r);
  182. build(p->ch[]);
  183. build(p->ch[]);
  184. }
  185. inline int Rank(int co,ScapeGoat_Tree *Root)
  186. {
  187. ScapeGoat_Tree *p=Root;
  188. int ret=;
  189. while(p!=null)
  190. if(p->col>=co)
  191. p=p->ch[];
  192. else
  193. ret+=p->ch[]->size+p->ex,p=p->ch[];
  194. return ret;
  195. }
  196. int query(ScapeGoat_Tree *p,int l,int r)
  197. {
  198. if(l>r)return 0x7fffffff;
  199. if(p==null)return 0x7fffffff;
  200. if(l<=&&r>=p->size)
  201. return p->min;
  202. int ans=0x7fffffff;
  203. if(p->ex&&l<=p->ch[]->size+p->ex&&r>=p->ch[]->size+p->ex)
  204. ans=p->key;
  205. if(l<=p->ch[]->size)
  206. ans=Min(ans,query(p->ch[],l,r));
  207. if(r>p->ch[]->size+p->ex)
  208. ans=Min(ans,query(p->ch[],l-(p->ch[]->size+p->ex),r-(p->ch[]->size+p->ex)));
  209. return ans;
  210. }
  211. inline int Query(int x)
  212. {
  213. int l=Rank(col[x],root[x]);
  214. int ans=query(root[x],,l);
  215. int r=Rank(col[x]+,root[x])+;
  216. ans=Min(ans,query(root[x],r,root[x]->size));
  217. return ans;
  218. }
  219. void update(Seg_Tree *p,int key)
  220. {
  221. if(key>Inf)return;
  222. p->size++;
  223. if(p->l==p->r)return;
  224. update(p->ch[p->mid<key],key);
  225. }
  226. inline void Init()
  227. {
  228. n=read(),m=read(),k=read(),q=read();
  229. for(int i=;i<=m;i++)
  230. e[i].x=read(),e[i].y=read(),e[i].z=read();
  231. Kruskal();
  232. for(int i=;i<=n;i++)col[i]=read();
  233. dfs();
  234. seg=New(,Inf);
  235. build(seg);
  236. for(int i=;i<=n;i++)
  237. update(seg,(Ans[i]=Query(i)));
  238. }
  239. inline void Del(int x)
  240. {
  241. pos[x]->ex=;
  242. ScapeGoat_Tree *p=pos[x];
  243. while(p!=null)
  244. p->pushup(),p=p->f;
  245. }
  246. void del(Seg_Tree *p,int key)
  247. {
  248. if(key>Inf)return;
  249. p->size--;
  250. if(p->l==p->r)return;
  251. del(p->ch[p->mid<key],key);
  252. }
  253. int get_ans(Seg_Tree *p)
  254. {
  255. if(p->l==p->r)return p->mid;
  256. if(p->ch[]->size)return get_ans(p->ch[]);
  257. else return get_ans(p->ch[]);
  258. }
  259. inline void work()
  260. {
  261. while(q--)
  262. {
  263. int x=read(),y=read();
  264. if(x!=)Del(x);
  265. if(x!=)if(root[f[x]]->bad())rebuild(root[f[x]]);
  266. col[x]=y;
  267. if(x!=)Insert(pos[x]->key,y,root[f[x]],x);
  268. del(seg,Ans[x]);
  269. if(x!=)del(seg,Ans[f[x]]);
  270. update(seg,(Ans[x]=Query(x)));
  271. if(x!=)update(seg,(Ans[f[x]]=Query(f[x])));
  272. printf("%d\n",get_ans(seg));
  273. }
  274. }
  275. int main()
  276. {
  277. pre();
  278. Init();
  279. work();
  280. return ;
  281. }

BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树的更多相关文章

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

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

  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. 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树

    [BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...

  4. BZOJ 4605 崂山白花蛇草水(权值线段树+KD树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4605 [题目大意] 操作 1 x y k 表示在点(x,y)上放置k个物品, 操作 2 ...

  5. 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

    题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...

  6. bzoj 2733: [HNOI2012]永无乡【并查集+权值线段树】

    bzoj上数组开大会T-- 本来想用set瞎搞的,想了想发现不行 总之就是并查集,每个点开一个动态开点的权值线段树,然后合并的时候把值并在根上,询问的时候找出在根的线段树里找出k小值,看看这个值属于哪 ...

  7. 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树

    经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...

  8. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

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

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

随机推荐

  1. python递归函数(计算阶乘)

    def f1(x,x1=1): if x == 1: return x1 #x1这个值为我们所需要的值,所以返回 x1 *= x r = f1(x-1,x1) #r接收返回值,并在下面接着返回 ret ...

  2. Leecode刷题之旅-C语言/python-14.最长公共前缀

    /* * @lc app=leetcode.cn id=14 lang=c * * [14] 最长公共前缀 * * https://leetcode-cn.com/problems/longest-c ...

  3. R语言学习笔记(八):零碎知识点(16-20)

    16--complete.cases( ) complete.case()可以判断对象中是否数据完全,然后返回TRUE, FALSE 这一函数在去除数据框中缺失值时很有用. > d kids a ...

  4. CPU计算密集型和IO密集型

    CPU计算密集型和IO密集型 第一种任务的类型是计算密集型任务,其特点是要进行大量的计算,消耗CPU资源,比如计算圆周率.对视频进行高清解码等等,全靠CPU的运算能力.这种计算密集型任务虽然也可以用多 ...

  5. C 二维指针难点详解。

    关于   指向二维数组的指针. int  a[2][3]; int *p; int (*p_1)[3]; 可以用p_1 = a ,但是不能用p = a : 因为此时数组a的数据类型是  int (* ...

  6. Hadoop Sentry 学习

    什么是Sentry? Sentry 是Cloudera 公司发布的一个Hadoop开源组件,它提供细粒度基于角色的安全控制 Sentry下的数据访问和授权 通过引进Sentry,Hadoop目前可在以 ...

  7. Returning Values from Bash Functions

    转自:https://www.linuxjournal.com/content/return-values-bash-functions Bash functions, unlike function ...

  8. Qt 编译时遇到 error: [debug/qrc_music.cpp] Error 1

    第一种方式,清理编译文件 把Qdebug release 文件件都删除, 删除makefile 文件 尝试重新编译 以上是网上寻找的结果 以下是我的解决方法 如果还抱错,请检查qrc文件是否存在异常 ...

  9. CentOS Linux release 7.5.1804下安装MySQL5.7.24

    1.环境查看: 2.卸载自带MariaDB数据库: 3.下载MySQL5.7.14安装包: 4.使用wget工具下载需要安装数据库的依赖包: 5.解压缩bundel包: 6.按照顺序进行安装: 7.数 ...

  10. [ubuntu 18.04 + RTX 2070] Anaconda3 - 5.2.0 + CUDA10.0 + cuDNN 7.4.1 + bazel 0.17 + tensorRT 5 + Tensorflow(GPU)

    (RTX 2070 同样可以在 ubuntu 16.04 + cuda 9.0中使用.Ubuntu18.04可能只支持cuda10.0,在跑开源代码时可能会报一些奇怪的错误,所以建议大家配置 ubun ...