种类并查集 + 离散化

//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;    //离散化,end
10 int n,m,l,r;    //输入,begin
11 char str[10];   //输入,end
12 
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()) {    //离散化,begin
55                 mp[l-1] = tot++;
56             }
57             if(mp.find(r)==mp.end()) {
58                 mp[r] = tot++;
59             }                               //离散化,end
60             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做离散化优化一下

转载于:https://www.cnblogs.com/AC-Phoenix/p/4264743.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值