题意:

给定一个无向图。每个点有一种颜色。现在给定q个询问,每次询问x和w,求所有能通过边权值不超过w的边走到x的点的集合中,哪一种颜色的点出现的次数最多。次数相同时输出编号最小的那个颜色。强制在线。

解题思路:膜拜大神们的代码!看了好久,终于搞懂了。

我们假设有一个二维数组存储了所有答案ans[x][w],那么对于每次查询,我们直接输出答案即可。关键在于怎么快速计算这个数组。我们先把图看成没有边的图,然后用克鲁斯卡尔最小生成树的思想,一条边一条边的加入,然后用并查集维护联通性。我们先从小枚举边,然后把该边插入图中。假设这条边的权值为2,那么这个时候,对于ans[x][2],我们可以用做一遍深搜就能计算出所有的ans[x][2]。怎么快速计算呢?我们可以用线段树去求,直接查询最大值即可。每个下标记录那个颜色的数量。每深搜到一个点就把该点插入到线段树,然后查询即可。但是这样总的复杂度还是O(NMlogN)的,仍然不可接受。这时候有一种神级做法,我们在做最小生成树的过程的时候,对于每一条 边新建一个节点,然后向边的两个节点连边,然后这个点通过线段树合并,继承那两个节点的信息。这样最后会形成一棵树,这棵树从底往上就是w从小到大的过程。最后对于每个查询,我们直接倍增看看能走到多高即可。

#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=210005,MAXM=200005;int N,M;
struct edge{int u,v,w;bool operator < (const edge &b)const{return w<b.w;}
}e[MAXM];int pre[MAXN*2];
int find(int x){return x==pre[x]?x:pre[x]=find(pre[x]);
}int root[MAXN*2];
int ls[MAXN*20];
int rs[MAXN*20];
int tree[MAXN*20];
int val[MAXN*20];
int tot=0;void pushup(int rt){if(tree[ls[rt]]>=tree[rs[rt]])//>=自然求得的就是数字最小的{tree[rt]=tree[ls[rt]];val[rt]=val[ls[rt]];}else{tree[rt]=tree[rs[rt]];val[rt]=val[rs[rt]];}
}void update(int L,int l,int r,int &rt){if(!rt)rt=++tot;if(l==r){tree[rt]=1;val[rt]=L;return;}int m=(l+r)/2;if(L<=m)update(L,l,m,ls[rt]);if(L>m)update(L,m+1,r,rs[rt]);pushup(rt);
}int merge(int L,int R,int l,int r){if(!L||!R)return L+R;if(l==r){tree[L]+=tree[R];return L;}int m=(l+r)/2;ls[L]=merge(ls[L],ls[R],l,m);rs[L]=merge(rs[L],rs[R],m+1,r);pushup(L);return L;
}int query(int rt){return val[rt];
}int col[MAXN*3];
int ans[MAXN*3];int dep[MAXN],fa[MAXN][20];
void init(){for(int i=0;i<MAXM;i++){pre[i]=i;root[i]=0;}tot=0;memset(ls,0,sizeof(ls));memset(rs,0,sizeof(rs));memset(tree,0,sizeof(tree));memset(val,0,sizeof(val));memset(fa,0,sizeof(fa));
}int P;
int ch[MAXN][2];
void kruskal(){P=N;sort(e,e+M);for(int i=0;i<M;i++){int u=e[i].u;int v=e[i].v;int fx=find(u);int fy=find(v);if(fx!=fy){col[++P]=e[i].w;ch[P][0]=fx;ch[P][1]=fy;pre[fx]=P;pre[fy]=P;}}
}void dfs(int u,int p){fa[u][0]=p;dep[u]=dep[p]+1;for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];if(u<=N)return;dfs(ch[u][0],u);dfs(ch[u][1],u);root[u]=merge(root[ch[u][0]],root[ch[u][1]],1,N);ans[u]=query(root[u]);
}int find(int x,int w){for(int i=19;i>=0;i--)if(col[fa[x][i]]<=w&&fa[x][i]!=0)x=fa[x][i];return x;
}int main(){int T;scanf("%d",&T);for(int qqq=1;qqq<=T;qqq++){init();scanf("%d%d",&N,&M);for(int i=1;i<=N;i++){scanf("%d",&col[i]);ans[i]=col[i];update(col[i],1,N,root[i]);}for(int i=0;i<M;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);kruskal();dfs(P,0);printf("Case #%d:\n",qqq);int Q;scanf("%d",&Q);int last=0;while(Q--){int u,x;scanf("%d%d",&u,&x);u=u^last;x=x^last;printf("%d\n",last=ans[find(u,x)]);}}return 0;
}

Gym - 101194G Pandaria (并查集+倍增+线段树合并)相关推荐

  1. Pandaria(Kruskal重构树+线段树合并)

    题意 是 有n个花园 一个花园内所有的花的颜色都是一样的 有很多种不同的颜色  花园到花园之间有路,走不同的路有不同的代价    如果选一个点作为起点 只走小于等于w的路  可以经过的这些花园里  那 ...

  2. POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)

    题意 在一个有N(1 ≤ N ≤ 1,000)个点环形图上有P(1 ≤ P ≤ 10,000)对点需要连接.连接只能连接环上相邻的点.问至少需要连接几条边. 思路 突破点在于最后的结果一定不是一个环! ...

  3. 【HDU - 4056】Draw a Mess (并查集 or 线段树)

    题干: It's graduated season, every students should leave something on the wall, so....they draw a lot ...

  4. 分门别类刷leetcode——高级数据结构(字典树,前缀树,trie树,并查集,线段树)

    目录 Trie树(字典树.前缀树)的基础知识 字典树的节点表示 字典树构造的例子 字典树的前序遍历 获取字典树中全部单词 字典树的整体功能 字典树的插入操作 字典树的搜索操作 字典树的前缀查询 字典树 ...

  5. Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G题, 并查集 + 线段树合并)

    题目链接  2016 ACM-ICPC EC-Final Problem G 题意  给定一个无向图.每个点有一种颜色. 现在给定$q$个询问,每次询问$x$和$w$,求所有能通过边权值不超过$w$的 ...

  6. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

  7. 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...

  8. Codeforces.1051G.Distinctification(线段树合并 并查集)

    题目链接 \(Description\) 给定\(n\)个数对\(A_i,B_i\).你可以进行任意次以下两种操作: 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\).必须存在 ...

  9. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...

最新文章

  1. 分布式服务框架 Zookeeper -- 管理分布式环境中的数据
  2. 品尝阿里云容器服务:5个2核4G节点使用情况记载
  3. CAD安装失败怎样卸载重新安装CAD,解决CAD安装失败的方法总结
  4. k-Means算法(Machine Learning in Action)基于python3.6
  5. 【实施工程师之家】linux安装tomcat(yum安装tomcat)
  6. ORA-12154: TNS:could not resolve the connect identifier specified. Solved.
  7. 程序员面试金典 - 面试题 10.05. 稀疏数组搜索(二分查找)
  8. 遇到一个在linux下无法跨网段发送接收广播包的问题
  9. redhat 7 oracle 11,redhat7 搭建oracle 11g RAC 问题与处理
  10. mysql备份恢复出错_MySQL:MySQL备份失败,原因和解决方式
  11. 泸州市的电子计算机学校名称,泸州电子计算机机械学校2020年招生简介
  12. Elasticsearch系列——实战探索text与keyword的区别
  13. 几种经典病毒动力学模型【基于matlab的动力学模型学习笔记_3】
  14. go日志收集系统项目简介
  15. 桌面图标小箭头去除方法
  16. 滴滴裁员2000人,员工竟然被裁出幸福感,获得员工的一致好评?
  17. CSS - 语法规则
  18. matlab拟合数据并输出公式,曲线拟合以及生成公式
  19. ES GEO地理空间查询java版
  20. 高速 CAN 总线收发器DP1040C PIN对PIN兼容TJA1040

热门文章

  1. 定义一个正整数的数组arr,删除arr数组中指定索引的元素,删除元素后面的元素需要往前移动,并且最后的索引位置用-1补上
  2. python自动化流程概念_python selenium 自动化流程的一些总结与思考
  3. 最新的一台联想式台式主机如何检查型号信息
  4. linux查看java环境变量
  5. 图论 物联网_图论算法-和图论算法相关的内容-阿里云开发者社区
  6. php执行sql语句
  7. shp转化为json
  8. Java之工具-------Junit自己的测试工具MyJUnit
  9. 从学习C++到用C++做外挂
  10. 一个人的宽度决定了他的高度