1.POJ 1733
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5744 | Accepted: 2233 |
Description
Input
Output
Sample Input
10 5 1 2 even 3 4 odd 5 6 even 1 6 even 7 10 odd
Sample Output
3
1.题目数据量较大,要用map来做哈希。
2.num[x]表示(fa[x],x]区间1的个数的奇偶性,0代表偶数,1代表奇数。以树根作为参照,每个点的num值即为树根到该点之间1的个数的奇偶性。
输入a,b
首先判断a,b是否在同一集合,如果在,则以其共同树根作为参照点,看异或值是否为0或1(0代表偶数,1代表奇数)。
如果不在,则合并两个集合,画一个图就知道了,图类似:http://www.cnblogs.com/whatbeg/p/3503585.html 中的图类似,假设fa[x] = y;
则 num[x] = num[a] ^ num[b] ^ k; (k = 0/1)
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> using namespace std; #define N 10100 int fa[N],num[N]; map<int,int> mp; void makeset(int n) { for(int i=1;i<=10000;i++) { fa[i] = i; num[i] = 0; } } int findset(int x) { if(x != fa[x]) { int tmp = fa[x]; fa[x] = findset(fa[x]); num[x] = num[x]^num[tmp]; } return fa[x]; } int unionset(int a,int b,char oe) { int x = findset(a); int y = findset(b); int k = (oe == 'o'? 1:0); if(x == y) { if(num[a]^num[b] == k) return 1; else return 0; } else { fa[x] = y; num[x] = num[a]^num[b]^k; return 1; } } int main() { int n,m,i,k,a,b,cnt; char ss[8]; scanf("%d%d",&n,&m); makeset(n); k = 1; cnt = 0; for(i=1;i<=m;i++) { scanf("%d%d %s",&a,&b,ss); a = a-1; if(mp.find(a) == mp.end()) { mp[a] = k++; } if(mp.find(b) == mp.end()) { mp[b] = k++; } if(unionset(mp[a],mp[b],ss[0])) cnt++; else break; } printf("%d\n",cnt); return 0; }
2.HDU 3038
题目大意:有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的,即命题为假的次数。
分析:与上面那题一样,用根节点作参照,每个点维护一个sum值,表示到根节点的距离,树根的距离为0。如果我们知道a到b之间的关系,a到c之间的关系,那么我们就可以知道a,b,c任意两个之间的关系。
输入a,b,判断是否属于同一集合,如果是,则判断 sum[b] - sum[a] 是否等于val。
如果不在同一集合,则合并,此时又画一个四点图可知, fa[y] = x; sum[y] = sum[b] - sum[a] + k; 不懂的话自己可以画一下。
然后就好搞了。
代码
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 200100 int fa[N],sum[N]; void makeset(int n) { for(int i=0;i<=n;i++) { fa[i] = i; sum[i] = 0; } } int findset(int x) { if(x != fa[x]) { int tmp = fa[x]; fa[x] = findset(fa[x]); sum[x] = sum[x] + sum[tmp]; } return fa[x]; } int unionset(int a,int b,int k) { int x = findset(a); int y = findset(b); if(x == y) { if(sum[b] - sum[a] == k) return 0; else return 1; } else { fa[y] = x; sum[y] = sum[a] - sum[b] + k; return 0; } } int main() { int n,m,i,a,b,cnt,val; while(scanf("%d%d",&n,&m)!=EOF) { makeset(n); cnt = 0; for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&val); a = a-1; if(unionset(a,b,val)) cnt++; } printf("%d\n",cnt); } return 0; }