并查集优化连边
Posted uid001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集优化连边相关的知识,希望对你有一定的参考价值。
很多题目均可用并查集优化连边, 跳过一些已经访问过的点
比方说, 对[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‘); }
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]," "[i==n]); } int main() { scanf("%d", &t); while (t--) work(); }
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 %d ", p+‘X‘, dis[p]); }
以上是关于并查集优化连边的主要内容,如果未能解决你的问题,请参考以下文章