题意:
BaoBao正在进行在线考试(都是选择题),每个题都有唯一的一个正确答案,但是考试系统有m个bug(就是有m个限制),每个bug表示为第u个问题和第v个问题你必须选择相同的选项,题目问你,如果你修好了第i个bug,BaoBao最高可以取得多少分。

题目数量1e5
BUG数量1e5(真多)
答案范围1e5

思路:首先,如果出现了bug,导致{a1,a2,...,an}n个题目必须选择一样的结果,那么最高得分肯定是众数的出现次数。我们发现bug是具有传递性的,如果bug连成了一个环,而且你只修复其中一个bug,那么这个bug的修复是对整个考试系统是没有任何影响的,所以我们不需要考虑这个环内的边,然后我们可以把这些环抠出来,缩成一个点,具体的缩点方法很多,也可以把整个块拉成一条链或者拓扑排序弄一弄,或者tarjan缩一下,我是用tarjan缩点的,这样整个图就是一个树了。
现在修一个bug就相当于断了一条边,一棵树就被切成两半了,我们需要同时得到两边的众数的个数是多少,这时候就有一个算法叫dsu on tree了,这是一个复杂度十分科学的暴力算法,http://codeforces.com/problemset/problem/600/E 这个题是一个dsu on tree的裸题,就是让你求每个子树的众数,不会这个算法的可以去学一下,做完这个题你就发现你会做子树内众数的个数了,现在还有个问题,子树外的怎么求呢?我们可以反过来做,一开始把所有的节点加进贡献里面去,然后dsu on tree的时候,询问子树众数的添加删除的时候,我们只要做相反的操作就行了。

具体细节还挺多的。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = ;struct Edge {
  4. int to,next,id;
  5. Edge(int _to=,int _next=-,int _id=):to(_to),next(_next),id(_id) {};
  6. } edge[maxn*];
  7. int head[maxn],etot;
  8. inline void addedge(int u,int v,int id) {
  9. edge[++etot]=Edge(v,head[u],id);
  10. head[u]=etot;
  11. }
  12. vector<int> nodes[maxn];
  13. int Cnt;
  14. int dfn[maxn],low[maxn],tot;
  15. bool Vis[maxn];
  16. int S[maxn],top;
  17. int id[maxn];
  18. void tarjan(int x,int fa) {
  19. low[x]=dfn[x]=++tot;
  20. S[++top]=x;
  21. Vis[x]=;
  22. for(register int i=head[x]; ~i; i=edge[i].next) {
  23. int v=edge[i].to;
  24. if(v==fa) {fa=;continue;}
  25. if(!dfn[v]) {
  26. tarjan(v,x);
  27. low[x]=min(low[x],low[v]);
  28. } else if(Vis[v])
  29. low[x]=min(low[x],dfn[v]);
  30. }
  31. if(low[x]==dfn[x]) {
  32. Cnt++;
  33. while() {
  34. int now=S[top--];
  35. Vis[now]=;
  36. id[now]=Cnt;
  37. nodes[Cnt].push_back(now);
  38. if(now==x) break;
  39. }
  40. }
  41. }
  42. int a[maxn],ans[maxn];
  43. vector<int>v[maxn];
  44. vector<int>edg[maxn],eid[maxn];
  45. int summ;
  46. bool vis[maxn];
  47. int sz[maxn],son[maxn];
  48. vector<int>vv;
  49. int getid(int x) {
  50. return lower_bound(vv.begin(),vv.end(),x)-vv.begin()+;
  51. }
  52. void init(int now,int pre=-){
  53. vis[now]=;
  54. sz[now]=v[now].size();
  55. for(int it:v[now])vv.push_back(a[it]);
  56. for(int to:edg[now]){
  57. if(to==pre)continue;
  58. init(to,now);
  59. sz[now]+=sz[to];
  60. if(!son[now]||sz[to]>sz[son[now]])
  61. son[now]=to;
  62. }
  63. }
  64. int tp[maxn],tp2[maxn],cnt[maxn],cnt2[maxn],Max=,Max2=;
  65. bool big[maxn];
  66. void update(int nows,int pre,int val){
  67. for(int now:v[nows]){
  68. tp[cnt[a[now]]]--;
  69. cnt[a[now]]+=val;
  70. tp[cnt[a[now]]]++;
  71. if(cnt[a[now]]>Max)
  72. Max=cnt[a[now]];
  73. if(!tp[Max])Max--;
  74. tp2[cnt2[a[now]]]--;
  75. cnt2[a[now]]-=val;
  76. tp2[cnt2[a[now]]]++;
  77. if(cnt2[a[now]]>Max2)
  78. Max2=cnt2[a[now]];
  79. if(!tp2[Max2])Max2--;
  80. }
  81. for(int to:edg[nows])
  82. if(to!=pre&&big[to]==)
  83. update(to,nows,val);
  84. }
  85. void update2(int nows,int pre,int val){
  86. for(int now:v[nows]){
  87. tp2[cnt2[a[now]]]--;
  88. cnt2[a[now]]+=val;
  89. tp2[cnt2[a[now]]]++;
  90. if(cnt2[a[now]]>Max2)
  91. Max2=cnt2[a[now]];
  92. if(!tp2[Max2])Max2--;
  93. }
  94. }
  95. int temp;
  96. void dfs(int now,int pre=-,int kep=,int id=){
  97. int tid=;
  98. for(register int i=;i<edg[now].size();i++){
  99. int to=edg[now][i];
  100. if(to==son[now])tid=eid[now][i];
  101. if(to==pre||to==son[now])continue;
  102. dfs(to,now,,eid[now][i]);
  103. }
  104. if(son[now])
  105. dfs(son[now],now,,tid),big[son[now]]=;
  106. update(now,pre,);
  107. ans[id]=Max+Max2-temp;
  108. big[son[now]]=;
  109. if(!kep)update(now,pre,-);
  110. }
  111. void init2(int now,int pre=-){
  112. for(int it:v[now])a[it]=getid(a[it]);
  113. update2(now,,);
  114. for(int to:edg[now]){
  115. if(to==pre)continue;
  116. init2(to,now);
  117. }
  118. }
  119. void solve(int now){
  120. vv.clear();
  121. init(now);
  122. for(register int i=;i<=sz[now];i++)tp[i]=tp2[i]=cnt[i]=cnt2[i]=big[i]=;Max=Max2=;
  123. sort(vv.begin(),vv.end());
  124. vv.erase(unique(vv.begin(),vv.end()),vv.end());
  125. init2(now);
  126. summ+=Max2;
  127. temp=Max2;
  128. dfs(now);
  129. }
  130. int main()
  131. {
  132. int T;
  133. scanf("%d",&T);
  134. while(T--){
  135. int n,m;
  136. scanf("%d%d",&n,&m);
  137. for(register int i=;i<=n;i++)head[i]=-,dfn[i]=son[i]=vis[i]=Vis[i]=,v[i].clear(),edg[i].clear(),eid[i].clear();
  138. etot=tot=Cnt=top=;
  139. for(register int i=;i<=n;i++)scanf("%d",a+i);
  140. for(register int i=;i<=m;i++){
  141. int u,v;
  142. scanf("%d%d",&u,&v);
  143. addedge(v,u,i);
  144. addedge(u,v,i);
  145. }
  146. for(register int i=;i<=n;i++)if(!dfn[i])tarjan(i,);
  147. for(register int i=;i<=n;i++)v[id[i]].push_back(i);
  148. summ=;
  149. for(register int i=;i<=n;i++){
  150. for(register int j=head[i];~j;j=edge[j].next){
  151. int u=id[i],to=id[edge[j].to];
  152. if(u==to){
  153. ans[edge[j].id]=;
  154. continue;
  155. }
  156. edg[u].push_back(to);eid[u].push_back(edge[j].id);
  157. }
  158. }
  159. for(register int i=;i<=Cnt;i++)
  160. if(!vis[i])
  161. solve(i);
  162. for(register int i=;i<=m;i++){
  163. if(i>)putchar(' ');
  164. printf("%d",ans[i]+summ);
  165. }
  166. puts("");
  167. }
  168. return ;
  169. }

2018 ACM-ICPC青岛现场赛 B题 Kawa Exam 题解 ZOJ 4059的更多相关文章

  1. hdu 4435 第37届ACM/ICPC天津现场赛E题

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题目:给出N个城市,从1开始需要遍历所有点,选择一 ...

  2. 2013 ACM/ICPC 长沙现场赛 A题 - Alice's Print Service (ZOJ 3726)

    Alice's Print Service Time Limit: 2 Seconds      Memory Limit: 65536 KB Alice is providing print ser ...

  3. 2013 ACM/ICPC 长沙现场赛 C题 - Collision (ZOJ 3728)

    Collision Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge There's a round medal ...

  4. 2018ACM/ICPC 青岛现场赛 E题 Plants vs. Zombies

    题意: 你的房子在0点,1,2,3,...,n(n<=1e5)点每个点都有一颗高度为0的花,浇一次水花会长a[i]. 你有一个机器人刚开始在你家,最多走m步,每一步只能往前走或者往后走,每走到一 ...

  5. hdu 4432 第37届ACM/ICPC天津现场赛B题

    题目大意就是找出n的约数,然后把约数在m进制下展开,各个数位的每一位平方求和,然后按m进制输出. 模拟即可 #include<cstdio> #include<iostream> ...

  6. 2016 年 ACM/ICPC 青岛区域赛 Problem C Pocky

    昨晚乱入学弟的训练赛,想了一下这个题.推导的过程中,加深了对公理化的概率论理解.$\newcommand{\d}{\mathop{}\!\mathrm{d}}$ 解法一 考虑 $ d < L$ ...

  7. 2013 ACM/ICPC 长沙网络赛J题

    题意:一个数列,给出这个数列中的某些位置的数,给出所有相邻的三个数字的和,数列头和尾处给出相邻两个数字的和.有若干次询问,每次问某一位置的数字的最大值. 分析:设数列为a1-an.首先通过相邻三个数字 ...

  8. 2013 ACM/ICPC 长春网络赛E题

    题意:给出一个字符串,要从头.尾和中间找出三个完全相等的子串,这些串覆盖的区间互相不能有重叠部分.头.尾的串即为整个字符串的前缀和后缀.问这个相同的子串的最大长度是多少. 分析:利用KMP算法中的ne ...

  9. 2013 ACM/ICPC 长春网络赛F题

    题意:两个人轮流说数字,第一个人可以说区间[1~k]中的一个,之后每次每人都可以说一个比前一个人所说数字大一点的数字,相邻两次数字只差在区间[1~k].谁先>=N,谁输.问最后是第一个人赢还是第 ...

随机推荐

  1. c#基础之abstract和interface

    一.abstract abstract 的词义是“抽象”,它用来定义抽象类.抽象类不能被实例化只能被继承. 定义抽象类的格式如下:public abstract ClassName{……} 注意:只有 ...

  2. vue 定义全局函数,监听android返回键事件

    vue 定义全局函数,监听android返回键事件 方法一:main.js 注入(1)在main.js中写入函数Vue.prototype.changeData = function (){ aler ...

  3. postgresql 表触发器

    1.先建一个函数,用来执行触发器启动后要执行的脚本 CREATE OR REPLACE FUNCTION "public"."trigger_day_aqi"( ...

  4. ABP入门系列之1——ABP总体介绍

    ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点, ...

  5. 第十一节 JS事件基础

    空白点击事件(没什么用处,做个介绍) <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  6. Py 最全的常用正则表达式大全 ZZ

    很多不太懂正则的朋友,在遇到需要用正则校验数据时,往往是在网上去找很久,结果找来的还是不很符合要求.所以我最近把开发中常用的一些正则表达式整理了一下,在这里分享一下.给自己留个底,也给朋友们做个参考. ...

  7. 大佬是怎么思考设计MySQL优化方案的?

    在进行MySQL的优化之前,必须要了解的就是MySQL的查询过程,很多查询优化工作实际上就是遵循一些原则,让MySQL的优化器能够按照预想的合理方式运行而已. 一.优化的哲学 注:优化有风险,涉足需谨 ...

  8. java截取2个指定字符之间的字符串

    /** * 截取字符串str中指定字符 strStart.strEnd之间的字符串 * * @param string * @param str1 * @param str2 * @return */ ...

  9. 使用littleTools简化docker/kubectl的命令

    littleTools littleTools是我根据日常运维时编写的一个小工具,开源在了https://github.com/xuxinkun/littleTools上. littleTools包含 ...

  10. HDFS配置参数及优化之实战经验(Linux hdfs)

    HDFS优化之实战经验 Linux系统优化 一.禁止文件系统记录时间 Linux文件系统会记录文件创建.修改和访问操作的时间信息,这在读写操作频繁的应用中将带来不小的性能损失.在挂载文件系统时设置no ...