首页 > 代码库 > 种类并查集
种类并查集
//http://acm.timus.ru/problem.aspx?space=1&num=1003
//分析:树和递归最常用的思想是分治;并查集是一种合并树的数据结构;合并树或加入树节点时,我们只在意新建立的树边上相邻的两个树节点之间的关系,实际上树边只在意相邻两个树节点之间的关系
//思路:可以讲一段连续区间的奇偶性表示成两个前缀和的奇偶性;将出现的离散的点用map离散化一下;将数量减少的点做一次种类并查集
1 #include"iostream" 2 #include"cstdio" 3 #include"cstring" 4 #include"map" 5 using namespace std; 6 const int N = 5010; 7 int rt[N<<1],w[N<<1]; //带权(种类)并查集 begin,end 8 map<int,int> mp; //离散化,begin 9 int tot; //离散化,end10 int n,m,l,r; //输入,begin11 char str[10]; //输入,end12 13 void paco(int a)14 {15 if(rt[a]==a) { //分治终点16 return ;17 }18 paco(rt[a]); //分治19 w[a] ^= w[rt[a]]; //回溯,begin 注:树根的w一定为0,我们只在意树边上的信息即可20 rt[a] = rt[rt[a]]; //回溯,end 注:我们只在意树边上的信息即可21 }22 23 bool unio(int a,int b,int cnd) //路径压缩 + 条件判断(合法性判断+树的合并)24 {25 paco(a);26 paco(b);27 int rt_a = rt[a],rt_b = rt[b];28 if(rt_a==rt_b) {29 return w[a]^w[b]^(!cnd); //搞个卡诺图化简一下30 }31 else {32 rt[rt_a] = rt_b;33 w[rt_a] = (w[a]+w[b]+cnd)&1; //搞个状态转换图推一下,因为树根的w为0,所以两根之间的关系就是新树边的w值 注:我们只在意树边上的信息即可34 }35 return true;36 }37 38 int main()39 {40 int i,res;41 bool ok;42 while(scanf("%d",&n)!=EOF&&n!=-1) {43 scanf("%d",&m);44 for(i = 0; i<=m; ++i) {45 rt[i] = i;46 }47 memset(w,0,sizeof(int)*(m+1));48 mp.clear();49 tot = 1;50 res = 0;51 ok = 1;52 for(i = 1; i<=m; ++i) {53 scanf("%d%d%s",&l,&r,str);54 if(mp.find(l-1)==mp.end()) { //离散化,begin55 mp[l-1] = tot++;56 }57 if(mp.find(r)==mp.end()) {58 mp[r] = tot++;59 } //离散化,end60 if(unio(mp[l-1],mp[r],str[0]==‘o‘)) {61 if(ok) {62 ++res;63 }64 }65 else {66 ok = 0;67 }68 }69 printf("%d\n",res);70 }71 return 0;72 }
//拓展:map具有对数搜索,去除和插入操作的复杂度,可以用hash做离散化优化一下
种类并查集
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。