並查集優化連邊
阿新 • • 發佈:2019-01-04
優化 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) usingView Codenamespace 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‘); }
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
並查集優化連邊