《算法竞赛进阶指南》 0x41 + 0x44 代码 + 杂谈
并查集
普通并查集
程序自动分析
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 5;
int n, m;
int pre[maxn];
void init(int n) {
for(int i = 1; i <= n; i++)
pre[i] = i;
}
int finds(int x) {
return pre[x] != x ? pre[x] = finds(pre[x]) : x;
}
void unions(int x, int y) {
x = finds(x), y = finds(y);
pre[x] = y;
}
signed main() {
fastio;
int t;
cin >> t;
while(t--) {
int cnt = 0;
cin >> n;
init(n * 2);
int x, y, d;
map<int, int> id;
vector<pair<int, int> >b;
while(n--) {
cin >> x >> y >> d;
if(!id[x])
id[x] = ++cnt;
if(!id[y])
id[y] = ++cnt;
if(d == 1) {
unions(id[x], id[y]);
} else {
b.push_back(make_pair(id[x], id[y]));
}
}
int f = 1;
for(int i = 0; i < b.size(); i++) {
if(finds(b[i].first) == finds(b[i].second)) {
cout << "NO" << endl;
f = 0;
break;
}
}
if(f) {
cout << "YES" << endl;
}
}
return 0;
}
银河英雄传说
加权并查集好写啊
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 30000 + 10;
int pre[maxn], siz[maxn], d[maxn];
void init(int n) {
for(int i = 1; i < maxn; i++) {
pre[i] = i, siz[i] = 1, d[i] = 0;
}
}
int finds(int x) {
if(x == pre[x])
return x;
int rt = finds(pre[x]);
d[x] += d[pre[x]];
return pre[x] = rt;
}
void unions(int x, int y) {
x = finds(x), y = finds(y);
pre[x] = y;
d[x] += siz[y];
siz[y] += siz[x];
}
int main() {
int n;
cin >> n;
init(n);
for(int i = 1; i <= n; i++) {
string cmd;
int x, y;
cin >> cmd >> x >> y;
if(cmd[0] == 'M') {
unions(x, y);
} else {
if(finds(x) != finds(y))
cout << -1 << endl;
else
cout << abs(d[x] - d[y]) - 1 << endl;
}
}
return 0;
}
parity game
奇数偶数性质 这里 异或 相当于差 奇数 + 奇数 = 偶数, 偶数 + 奇数 = 奇数
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int fa[maxn], d[maxn];
int a[maxn];
struct node{
int l, r, ans;
}que[maxn];
void init(){
for(int i = 0; i < maxn ; i ++ ) fa[i] = i;
}
int finds(int x){
if(x == fa[x]) return x;
int rt = finds(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = rt;
}
int main(){
int n, m;
cin >> n >> m;
string str;
int cnt = 0;
for(int i = 1, x, y; i <= m; i ++ ) {
cin >> x >> y >> str;
if(str[0] == 'o'){
que[i] = node{x, y, 1};
}else{
que[i] = node{x, y, 0};
}
a[++cnt] = x - 1;
a[++cnt] = y;
}
sort(a + 1, a + 1 + cnt);
cnt = unique(a + 1, a + 1 + cnt) - a - 1;
init();
for(int i = 1, x, y; i <= m; i ++ ){
x = lower_bound(a + 1, a + 1 + cnt, que[i].l - 1) - a;
y = lower_bound(a + 1, a + 1 + cnt, que[i].r) - a;
int p = finds(x), q = finds(y);
if(p == q) {
if(d[x] ^ d[y] != que[i].ans) {
cout << i - 1 << endl;
return 0;
}
}else{
fa[p] = q;
d[p] = d[x] ^ d[y] ^ que[i].ans;
}
}
cout << m << endl;
return 0;
}
食物链 入门题
#include <iostream>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int maxn=200000+10;
const int gxs = 3;
int n,m;
const int mod=3;
int pre[maxn],rnk[maxn];
//查找
void init(){
for(int i=0;i<maxn;i++) pre[i]=i,rnk[i]=0;
}
int finds(int x)
{
if(x==pre[x]) return x;
else
{
int root=finds(pre[x]); // 找到根节点
rnk[x]+=rnk[pre[x]]; // 权值合并,更新
rnk[x]%=mod;
return pre[x]=root; // 压缩路径
}
}
//新建关系
void join(int x,int y,int s)
{
int fx=finds(x);
int fy=finds(y);
if (fx!=fy)
{
pre[fy]=fx;
rnk[fy]=rnk[x]-rnk[y]+s+mod;
rnk[fy]%=mod;
}
}
void unions(int x,int y,int m){
int a=finds(x),b=finds(y);
if(a!=b){
pre[b]=a;
rnk[b]=rnk[x]+m-rnk[y];
rnk[b]+=gxs;
rnk[b]%=gxs;
}
}
int main() {
int b,a,k;
cin>>n>>m;
init();
int ans=0;
for(int i=0;i<m;i++){
cin>>k>>a>>b;
if((k==2&&a==b)||a>n||b>n||a<=0||b<=0) {
ans++;
}
else if(k==1){
if(finds(a)==finds(b)&&(rnk[a]!=rnk[b])) ans++;
else unions(a,b,0);
}
else if(k==2){
if(finds(a)==finds(b)&&(rnk[a])!=(rnk[b]+2)%mod) ans++;
else unions(a,b,1);
}
}
cout<<ans<<endl;
return 0;
}
补充 倒着处理 + 联通
P1197 [JSOI2008]星球大战
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int maxn=4e5+10;
int n,m,k;
int pre[maxn];
void init(){for(int i=0;i<maxn;i++) pre[i]=i;}
inline int finds(int x){return pre[x]!=x?pre[x]=finds(pre[x]):x;}
inline void unions(int x,int y){x=finds(x);y=finds(y);x!=y?pre[x]=y:1;}
struct node{
int a,b,t;
bool operator < (const node & c){
return c.t>t;
}
};
vector<node> que;
map<int,int> mp;
vector<int> ans;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
int a,b,t;
init();
for(int i=0;i<m;i++){
cin>>a>>b;
que.push_back(node{a,b,0});
}
cin>>k;
for(int i=1;i<=k;i++){
cin>>a;
mp[a]=k-i+1;
}
for(int i=0;i<m;i++){
que[i].t=max(mp[que[i].a],mp[que[i].b]);
}
sort(que.begin(),que.end());
int cnt=n;
int pre=0;
for(int i=0,j=0;i<=k;i++){
for(;que[j].t==i;j++){
if(finds(que[j].a)!=finds(que[j].b)){
unions(que[j].a,que[j].b);
cnt--;
}
}
ans.push_back(cnt-(k-i));
}
for(int i=k;i>=0;i--){
cout<<ans[i]<<endl;
}
return 0;
}
分块
orz 只作了最简单的 分块入门
简单区间修改 区间求和
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll a[maxn], sum[maxn], add[maxn];
int L[maxn], R[maxn];
int pos[maxn];
void change(int l, int r, ll d) {
int p = pos[l], q = pos[r];
if(p == q) {
for(int i = l; i <= r; i ++)
a[i] += d;
sum[p] += d * (r - l + 1);
} else {
for(int i = p + 1; i <= q - 1; i ++)
add[i] += d;
for(int i = l; i <= R[p]; i ++)
a[i] += d;
sum[p] += d * (R[p] - l + 1);
for(int i = L[q]; i <= r; i ++)
a[i] += d;
sum[q] += d * (r - L[q] + 1);
}
}
ll ask(int l, int r) {
int p = pos[l], q = pos[r];
ll res = 0;
if(p == q) {
for(int i = l; i <= r; i ++)
res += a[i];
res += add[p] * (r - l + 1);
} else {
for(int i = p + 1; i <= q - 1; i ++)
res += sum[i] + add[i] * (R[i] - L[i] + 1);
for(int i = l; i <= R[p]; i ++)
res += a[i];
res += add[p] * (R[p] - l + 1);
for(int i = L[q]; i <= r; i ++)
res += a[i];
res += add[q] * (r - L[q] + 1);
}
return res;
}
int main() {
int n, m;
cin >> n >> m;
for(int i = 1; i <= n ; i ++)
cin >> a[i];
double tp = sqrt(n);
int t = int(tp);
for(int i = 1; i <= t; i ++) {
L[i] = (i - 1) * tp + 1;
R[i] = i * tp;
}
if(R[t] < n)
t ++, L[t] = R[t - 1] + 1, R[t] = n;
for(int i = 1; i <= t; i ++) {
for(int j = L[i]; j <= R[i]; j ++) {
pos[j] = i;
sum[i] += a[j];
}
}
int cmd;
for(int i = 1, l, r, d; i <= m ; i++) {
cin >> cmd;
if(cmd == 1) {
cin >> l >> r >> d;
change(l, r, d);
} else {
cin >> l >> r;
cout << ask(l, r) << endl;
}
}
return 0;
}