《算法竞赛进阶指南》 0x41 + 0x44 代码 + 杂谈

并查集

普通并查集
程序自动分析

#include 
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 
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 
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 
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 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
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;
}

你可能感兴趣的:(题集,《算法竞赛进阶指南》杂谈)