1. 程式人生 > >並查集優化連邊

並查集優化連邊

優化 unsigned span type dijkstra ces oid color 二維

很多題目均可用並查集優化連邊, 跳過一些已經訪問過的點

比方說, 對[L,R]範圍進行一定更新可以這樣寫

for (int i=Find(L); i<=R; i=Find(i)) {
    //do something
    fa[i] = i+1;
}

這樣操作過後[L,R]的fa均指向R+1, 下一次會直接跳到R+1, 相當於每個點值只更新一次

例題

1, CF 827A

求構造一個最小字典序的字符串, 其中字符串某些位置的字符固定

技術分享圖片
#include <iostream>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using
namespace std; const int N = 2e6+10, INF = 0x3f3f3f3f; int n, m; int fa[N]; int Find(int x) {return fa[x]==x?x:fa[x]=Find(fa[x]);} char s[N], t[N]; int main() { scanf("%d", &n); REP(i,1,N-1) fa[i]=i; int mx = 0; REP(i,1,n) { scanf("%s", t+1); m = strlen(t+1);
int c, pos; scanf("%d", &c); while (c--) { scanf("%d", &pos); for (int j=Find(pos); j<=pos+m-1; j=Find(j)) { s[j] = t[j-pos+1]; fa[j] = j+1; } mx = max(mx, pos+m-1); } } REP(i,1
,mx) putchar(s[i]?s[i]:a); }
View Code

2, hdu 5361

直線上n個點, 點i能到達到i距離[li,ri]範圍內的點, 花費ci, 求單源最短路

技術分享圖片
#include <iostream>
#include <string.h>
#include <set>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define x first
#define y second
using namespace std;
typedef unsigned long long ll;
typedef pair<ll,int> pii;
const int N = 4e5+10;
const ll INF = 1LL<<60;
ll L[N], R[N], c[N], d[N];
int n, m, t, fa[N];
int Find(int x) {return fa[x]?fa[x]=Find(fa[x]):x;}

void dijkstra() {
    memset(d, 0x3f, sizeof d);
    memset(fa, 0, sizeof fa);
    set<pii> q;
    d[1] = 0;
    q.insert(make_pair(c[1],1));
    fa[1]=2;
    while (q.size()) {
        int u = q.begin()->y;q.erase(q.begin());
        for (int i:{-1,1}) {
            int l = u+i*L[u], r = u+i*R[u];
            if (l>r) swap(l,r);
            if (l>n||r<1) continue;
            l = max(1,l), r = min(n,r);
            for (int j=Find(l); j<=r; j=Find(j)) {
                if (j>r||j<l) break;
                if (d[j]>d[u]+c[u]) {
                    d[j]=d[u]+c[u];
                    q.insert({d[j]+c[j],j});
                }
                fa[j] = j+1;
            }
        }
    }
}


void work() {
    scanf("%d", &n);
    REP(i,1,n) scanf("%lld",L+i);
    REP(i,1,n) scanf("%lld",R+i);
    REP(i,1,n) scanf("%lld",c+i);
    dijkstra();
    REP(i,1,n) printf("%lld%c", d[i]>=d[0]?-1:d[i]," \n"[i==n]);
}

int main() {
    scanf("%d", &t);
    while (t--) work();
}
View Code

3, bzoj 2143

hdu的二維情況

技術分享圖片
#include <iostream>
#include <queue>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii;

const int N = 200;
int a[N][N], b[N][N], d[N][N], fa[N][N];
int n, m;
pii s[3];

struct _ {
    int x, y, w;
    bool operator < (const _ & rhs) const {
        return w>rhs.w;
    }
};

int Find(int fa[], int x) {return fa[x]==x?x:fa[x]=Find(fa,fa[x]);}

void dijkstra(pii s) {
    REP(i,1,n+20) REP(j,1,m+20) fa[i][j]=j;
    REP(i,1,n+20) REP(j,1,m+20) d[i][j]=0x3f3f3f3f;
    priority_queue<_> q;
    d[s.x][s.y]=0;
    q.push({s.x,s.y,a[s.x][s.y]});
    while (q.size()) {
        int x=q.top().x,y=q.top().y;q.pop();
        int l=max(1,x-b[x][y]),r=min(n,x+b[x][y]);
        REP(i,l,r) {
            int len = b[x][y]-abs(i-x);
            int u=max(1,y-len),D=min(m,y+len);
            for (int j=Find(fa[i],u); j<=D; j=Find(fa[i],j)) {
                if (d[i][j]>d[x][y]+a[x][y]) {
                    d[i][j]=d[x][y]+a[x][y];
                    q.push({i,j,d[i][j]+a[i][j]});
                }
                fa[i][j] = j+1;
            }
        }
    }
}

int dis[3];

int main() {
    scanf("%d%d", &n, &m);
    REP(i,1,n) REP(j,1,m) scanf("%d",&b[i][j]);
    REP(i,1,n) REP(j,1,m) scanf("%d",&a[i][j]);
    REP(i,0,2) scanf("%d%d",&s[i].x,&s[i].y);
    char ans = 0;
    int mi = 1e9;
    REP(i,0,2) { 
        dijkstra(s[i]);
        REP(j,0,2) dis[j] += d[s[j].x][s[j].y];
    }
    int p=min_element(dis,dis+3)-dis;
    if (dis[p]>1e8) return puts("NO"),0;
    printf("%c\n%d\n", p+X, dis[p]);
}
View Code

並查集優化連邊