【Up主又更新了个说..】
【UFS,Union_Find_Set】
说到这个带权并查集,我真的是第一次接触这种维护相对关系类型的。
所以各种不会,各种被虐,各种欲哭无泪。TAT若菜的烦恼你们会懂?
算了不说了...满纸荒唐言,一把辛酸泪....我发现我真的是个NC完全问题..NC到一种境界了。
直接上代码吧。我也不知道具体该说些什么。以后想补或者有人问(估计没人问,都是因为我太弱了...)再补上题解吧。
题目1:
Lyp的战斗记录
lyp.pas/lyp.in/lyp.out
众所周知,我们的lyp神犇外号叫Altman,的确,在另一个平行宇宙,lyp神犇就是一个——Altman。
有一天,lyp神犇遇到了另一个平行宇宙中的他,得知了在其他的宇宙中,Altman是存在的,那么,怪兽也是存在的咯。
作为一个有名的oier,lyp神犇想要统计一下各个宇宙中怪兽的战斗力,他发现,一些怪兽在不同的宇宙都出现过(!. !,难不成怪兽不穿越,算了,不管了),每一个Altman都提供给lyp一些信息,告诉他一个怪兽比另一个怪兽的战斗力大多少(这个数可以是负数)。
Altman神犇为了给你以表现机会,将这些信息都给你,并会时不时地问你两个怪兽之间谁更强。
假设Altman们提到了怪兽都按1~n编号。
Altman们的信息的格式是 X A B C
其中x固定为1,A,B是两个1~n的整数,表示怪兽编号,A怪兽的战斗力比B怪兽的战斗力大C(C为整数),保证信息之间不矛盾。
Lyp的询问的格式是:Y A B
Y 固定为2,A,B是怪兽编号,属于1~n,如果A比B 强,输出A;如果B比A强,输出B,如果无法判断或怪兽们一样强,输出0
【输入格式】: 第1行,两个数n,q,n表示怪兽总数,q表示询问与信息的总数;
第2~q+1 行, 每一行是一个信息或询问,格式如题;
【输出格式】: 对于每一个询问,用单独一行回答。
【样例】:input 3 3
1 1 2 3
1 3 2 1
2 1 3
Output 1
【数据约定】: 30% n<=100 q<=300
100% n<=30000 q<=50000 c的绝对值不超过5000
这道题注意一点:
我是第一次写非递归并查集,然后犯了这么一个错误:
for (; k != ff; ww -= w[k], k = f[k]) f[k] = ff, w[k] = ww;
这个实际上效率不高,因为相当于只把k连到了代表元上。要真真实现压缩路径,要这么写。
while (k != ff) t = f[k], f[k] = ff, u = w[k], w[k] = ww, ww -= u, k = t;
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#ifdef WIN32
#define otl "%I64d"
#else
#define otl "%lld"
#endif
//#define link(a, b) ({nt[++tot] = h[a]; t[h[a] = tot] = b; nt[++tot] = h[b]; t[h[b] = tot] = a;})
#define Max(t, a, b) ({t _ = (a), __ = (b); _ > __ ? _ : __;})
#define Min(t, a, b) ({t _ = (a), __ = (b); _ < __ ? _ : __;})
#define swap(t, a, b) ({t _ = (a); (a) = (b); (b) = _;})
#define maxn 30005
using namespace std;
int f[maxn], w[maxn], n, q;
void init()
{
freopen("lyp.in", "r", stdin);
freopen("lyp.out", "w", stdout);
scanf(ot ot, &n, &q);
for (int i = 1; i <= n; ++i) f[i] = i;
memset(w, 0, sizeof w);
}
int find(int k)
{
int ff = k, ww = 0, t, u;
while (f[ff] != ff) ww += w[ff], ff = f[ff];
while (k != ff) t = f[k], f[k] = ff, u = w[k], w[k] = ww, ww -= u, k = t;
//for (; k != ff; ww -= w[k], k = f[k]) f[k] = ff, w[k] = ww; Wrong!!!
return ff;
}
int main()
{
init();
int ask, x, y, z, fx, fy;
for (int i = 1; i <= q; ++i)
{
scanf(ot ot ot, &ask, &x, &y);
fx = find(x), fy = find(y);
if (ask == 1)
{
scanf(ot, &z);
if (fx != fy) w[fx] = z + w[y] - w[x], f[fx] = fy;
}
else if(ask == 2)
{
if (fx != fy || w[x] == w[y]) printf("0");
else if (w[x] > w[y]) printf(ot, x);
else printf(ot, y);
printf("\n");
}
}
return 0;
}
题目2
输入
第一行一个数n表示序列长度。
接下来两行每行n个数,表示一个序列。
要求交换这两个序列中的某些位置相同的数字,使得两个序列中均无重复数字。输出最少交换次数。
数据保证有解。
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define max(a, b) ({int _ = (a), __ = (b); _ > __ ? _ : __;})
using namespace std;
int n, a, cnt[2][100005], t[2][2][100005], num[100005], f[100005], w[100005], mx;
void init()
{
freopen("dwu.in", "r", stdin);
freopen("dwu.out", "w", stdout);
scanf(ot, &n);
mx = -INT_MAX;
memset(num, 0, sizeof num);
for (int p = 0; p <= 1; ++p)
for (int i = 1; i <= n; ++i)
scanf(ot, &a), t[num[a]][0][a] = p, t[num[a]++][1][a] = i, mx = max(mx, a);
}
int find(int k)
{
int ww = 0, ff = k, t, cw;
while (f[ff] != ff) ww ^= w[ff], ff = f[ff];
while (f[k] != k)
cw = w[k], w[k] = ww, ww ^= cw, t = f[k], f[k] = ff, k = t;
return ff;
}
int main()
{
init();
for (int i = 1; i <= n; ++i) f[i] = i;
int fx, fy, x, y;
for (int i = 1; i <= mx; ++i)
if (num[i] == 2)
{
x = t[0][1][i]; y = t[1][1][i];
fx = find(x); fy = find(y);
if (fx != fy) w[fx] = (int)(t[0][0][i] == t[1][0][i]) ^ w[y] ^ w[x], f[fx] = fy;
}
for (int i = 1; i <= n; ++i) if (f[i] != i) find(i), ++cnt[w[i]][f[i]]; else ++cnt[0][f[i]];
int ans = 0;
for (int i = 1; i <= n; ++i) if (f[i] == i) ans += min(cnt[0][i], cnt[1][i]);
printf(ot, ans);
return 0;
}
3.POJ1733
给定未知的01串,每次描述从x到y位中1的个数为奇数还是偶数
问多少次后矛盾。
TAT空间开小了调试了半天...
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define swap(a, b) ({int _ = a; a = b; b = _;})
#define ot "%d"
#define maxn 100005
using namespace std;
int n, len, f[maxn << 3], w[maxn << 3], q[3][maxn << 3], d[3][maxn << 3], v[maxn << 3], c;
void sort(int l, int r)
{
int i = l, j = r, x = v[(l + r) >> 1];
while (i <= j)
{
while (v[i] < x) ++i;
while (v[j] > x) --j;
if (i <= j)
{
swap(v[i], v[j]);
swap(d[0][i], d[0][j]);
swap(d[1][i], d[1][j]);
swap(d[2][i], d[2][j]);
++i, --j;
}
}
if (i < r) sort(i, r);
if (l < j) sort(l, j);
}
void init()
{
freopen("shame.in", "r", stdin);
freopen("shame.out", "w", stdout);
scanf(ot ot "\n", &n, &len);
char ch[10];
int nn = n << 1;
for (int i = 1; i <= (nn << 2) + 1; ++i) f[i] = i;
for (int i = 1, j = 1; i <= nn; i += 2, ++j)
{
scanf("%d %d %s\n", &v[i], &v[i + 1], ch);
d[0][i] = 0, d[1][i] = j, d[2][i] = (int)(ch[0] == 'o');
d[0][i + 1] = 1, d[1][i + 1] = j, d[2][i + 1] = (int)(ch[0] == 'o');
}
sort(1, nn);
int t = 0;
for (int i = 1; i <= nn; ++i)
{
if (v[i] != v[i - 1]) ++t;
q[d[0][i]][d[1][i]] = t << 1, q[2][d[1][i]] = d[2][i];
}
}
int find(int k)
{
int ff = k, ww = 0, t, cw;
while (f[ff] != ff) ww ^= w[ff], ff = f[ff];
while (k != ff) cw = w[k], w[k] = ww, ww ^= cw, t = f[k], f[k] = ff, k = t;
return ff;
}
int main()
{
init();
int x, y, fx, fy, flag = 0;
memset(w, 0, sizeof w);
for (int i = 1; i <= n; ++i)
{
c = q[2][i], x = q[0][i], y = q[1][i] + 1;
fx = find(x), fy = find(y);
if (fx != fy)
{
f[fx] = fy;
w[fx] = w[x] ^ w[y] ^ c;
}
else
if (w[x] ^ w[y] != c)
{
printf(ot, i);
flag = 1;
break;
}
}
if (!flag) printf("-1");
return 0;
}