复习 [kuangbin带你飞]专题5 并查集

news2024/11/16 19:49:53

目录

  • 1. poj 2236 Wireless Network
  • 2. poj 1611 The Suspects
  • 3. hdu 1213 How Many Tables
  • 4. hdu 3038 How Many Answers Are Wrong
  • 5. poj 1182 食物链
  • 6. poj 1417 True Liars
  • 7. poj 1456 Supermarket
  • 8. poj 1733 Parity game
  • 9. poj1984 Navigation Nightmare
  • 10. poj 2912 A Bug's Life
  • 11. poj 2912 Rochambeau
  • 12. ZOJ-3261 Connections in Galaxy War
  • 13. hdu 1272 小希的迷宫
  • 14. poj 1308 Is It A Tree?

1. poj 2236 Wireless Network

  • 水题
#include <iostream>
using namespace std;
const int MAXN = 2e5+100;
int set[MAXN];
int rank[MAXN];
struct NODE{
	int x,y;
}node[MAXN];
int FIND_PATH(int x){
	if(x == set[x]) return x;
	return set[x] = FIND_PATH(set[x]);
}
void UNION(int x,int y){
	x = FIND_PATH(x);
	y = FIND_PATH(y);
	if(x == y) return;
	if(rank[x] > rank[y]) set[y] = set[x];
	else{
		set[x] = set[y];
		if(rank[x] == rank[y]) rank[y]++;
	}
}
int dis(NODE X,NODE Y){
	int dx = X.x - Y.x;
	int dy = X.y - Y.y;
	return (dx * dx + dy * dy);
}
int vis[MAXN];
int main(){
	char c;
	int n,d,m,p;
	cin>>n>>d;
	for(int i=1;i<=n;i++) set[i] = i;
	for(int i=1;i<=n;i++) cin>>node[i].x>>node[i].y;
	while(cin>>c){
		if(c == 'O'){
			cin>>m;
			for(int i=1;i<=n;i++){
				if(vis[i]&&i!=m&&dis(node[m],node[i])<=d*d){
					UNION(i,m);
				}
			} 
			vis[m] = 1;
		}else if(c == 'S'){
			cin>>m>>p;
			if(FIND_PATH(m) == FIND_PATH(p)) cout<<"SUCCESS"<<endl;
			else cout<<"FAIL"<<endl;
		}
	}
	return 0;
}

2. poj 1611 The Suspects

#include <iostream>
using namespace std;
const int MAXN = 2e5+100;
int set[MAXN];
int rank[MAXN];
struct NODE{
	int x,y;
}node[MAXN];
int FIND_PATH(int x){
	if(x == set[x]) return x;
	return set[x] = FIND_PATH(set[x]);
}
void UNION(int x,int y){
	x = FIND_PATH(x);
	y = FIND_PATH(y);
	if(x == y) return;
	if(rank[x] > rank[y]) set[y] = set[x];
	else{
		set[x] = set[y];
		if(rank[x] == rank[y]) rank[y]++;
	}
}
int main(){
	int n,m,p,x,y;
	while(cin>>n>>m){
		if(n == 0&&m == 0) break;
		for(int i=0;i<n;i++) set[i] = i;
		while(m--){
			cin>>p>>x;
			for(int i=1;i<p;i++){
				cin>>y;
				UNION(x,y);
			}
		}
		int ans = 0;
		for(int i=0;i<n;i++){
			if(FIND_PATH(i) == FIND_PATH(0)) ans++;
		}cout<<ans<<endl;
	}
	return 0;
}

3. hdu 1213 How Many Tables

  • 水题
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n, m;
        cin >> n >> m;
        vector<int> s(n + 1);
        for(int i=1;i<=n;i++) s[i] = i;
        function<int(int)> FIND = [&](int u){
            return s[u] == u ? u : s[u] = FIND(s[u]);
        };
        for(int i=0;i<m;i++){
            int u, v;
            cin >> u >> v;
            u = FIND(s[u]);
            v = FIND(s[v]);
            s[u] = v;
        }
        int ans = 0;
        for(int i=1;i<=n;i++){
            if(i == FIND(i)) ans += 1;
        }
        cout << ans << '\n';
    }
    return 0;
}

4. hdu 3038 How Many Answers Are Wrong

给出若干个区间加法关系,让你判断这里面有多少错误

  • 此题是带权并查集
  • 我们来研究一下权值的更新过程,假设输入 u , v , w u,v,w u,v,w,先画出下面的图
    在这里插入图片描述
  • 上图表示 u u u的祖先节点是 f u fu fu v v v的祖先节点是 f v fv fv v a l val val数组的含义是当前节点相对于祖先节点的权值,如果现在要合并 u u u v v v,那么我们要合并 f u fu fu f v fv fv
    在这里插入图片描述
  • 那么假设我们现在以 f v fv fv为祖先节点进行合并,那么显然两条路径权值应该相等,所以有 v a l [ u ] + v a l [ f u ] = v a l [ v ] + w val[u]+val[fu]=val[v]+w val[u]+val[fu]=val[v]+w,而现在我们要求的是 v a l [ f u ] val[fu] val[fu],所以有 v a l [ f u ] = v a l [ v ] − v a l [ u ] + w val[fu]=val[v]-val[u]+w val[fu]=val[v]val[u]+w
  • 上面是合并的例子,如果我们现在已经发现 u u u v v v已经处于一个集合,那么有下图
    在这里插入图片描述
  • 注意我们已经进行路径压缩,所以 u u u f v fv fv的总长为 v a l [ u ] val[u] val[u],那么此时应该进行验证了,应该有 w + v a l [ v ] = v a l [ u ] w+val[v]=val[u] w+val[v]=val[u],如果不满足说明出现矛盾
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m;
    while(cin >> n >> m){
        vector<int> s(n + 1);
        vector<int> val(n + 1);
        for(int i=1;i<=n;i++) s[i] = i;
        function<int(int)> FIND = [&](int u){
            if(u != s[u]){
                int fa = s[u];
                s[u] = FIND(fa);
                val[u] += val[fa];
            }
            return s[u];
        };
        int ans = 0;
        while(m--){
            int u, v, w;
            cin >> u >> v >> w;
            u -= 1;
            int fu = FIND(u);
            int fv = FIND(v);
            if(fu == fv){
                if(val[u] - val[v] != w){
                    ans += 1;
                }
            }else{
                s[fu] = fv;
                val[fu] = w + val[v] - val[u];
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

5. poj 1182 食物链

  • 扩展域并查集
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <numeric>
#include <set>
#include <stack>

using namespace std;

typedef long long ll;

const int N = 5e4 + 100;
int st[N * 3];
int FIND(int x){
  return x == st[x] ? x : st[x] = FIND(st[x]);
}
void Merge(int x, int y){
  int fx = FIND(x);
  int fy = FIND(y);
  if(fx != fy){
    st[fx] = fy;
  }
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, k;
  cin >> n >> k;
  for(int i=1;i<=3*n;i++){
    st[i] = i;
  }
  int ans = 0;
  for(int i=0;i<k;i++){
    int d, x, y;
    cin >> d >> x >> y;
    if(x > n || y > n){
      ans += 1;
      continue;
    }
    if(x == y && d == 2){
      ans += 1;
      continue;
    }
    if(d == 1){
      if(FIND(x) == FIND(y + n) || FIND(x) == FIND(y + 2 * n)){
        ans += 1;
        continue;
      }
      Merge(x, y);
      Merge(x + n, y + n);
      Merge(x + 2 * n, y + 2 * n);
    }else{
      if(FIND(x) == FIND(y) || FIND(x) == FIND(y + 2 * n)){
        ans += 1;
        continue;
      }
      Merge(x, y + n);
      Merge(x + n, y + 2 * n);
      Merge(x + 2 * n, y);
    }
  }
  cout << ans << '\n';
  return 0;
}

6. poj 1417 True Liars

  • 带权并查集+dp
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;
const int N = 700;

int fa[N], val[N];
int dp[N][N]; // dp[i][j]表示存储到第i个集合, 选择种类和为j的方法数
int path[N][N];
int vis[N][2];
int FIND(int x){
  if(x != fa[x]){
    int root = FIND(fa[x]);
    val[x] ^= val[fa[x]];
    fa[x] = root;
  }
  return fa[x];
}
void Merge(int u, int v, int d){
  int fu = FIND(u);
  int fv = FIND(v);
  if(fu != fv){
    fa[fv] = fu;
    val[fv] = val[u] ^ val[v] ^ d;
  }
}
int g[N];
int tag[N][2];
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, p1, p2;
  while(cin >> n >> p1 >> p2){
    if(n + p1 + p2 == 0) break;
    for(int i=1;i<=p1+p2;i++) fa[i] = i;
    memset(vis, 0, sizeof vis);
    memset(dp, 0, sizeof dp);
    memset(path, 0, sizeof path);
    memset(val, 0, sizeof val);
    memset(tag, 0, sizeof tag);
    memset(g, 0, sizeof g);
    for(int i=0;i<n;i++){
      int u, v;
      string s;
      cin >> u >> v >> s;
      if(s[0] == 'y'){
        Merge(u, v, 0);
      }else{
        Merge(u, v, 1);
      }
    }
    int cnt = 0;
    for(int i=1;i<=p1+p2;i++){
      if(i == FIND(i)) g[i] = ++cnt;
    }
    for(int i=1;i<=p1+p2;i++){
      tag[g[FIND(i)]][val[i]] += 1;
    }
    dp[0][0] = 1;
    for(int i=1;i<=cnt;i++){
      for(int j=0;j<=p1+p2;j++){
        if(j - tag[i][0] >= 0 && dp[i - 1][j - tag[i][0]]){
          dp[i][j] += dp[i - 1][j - tag[i][0]];
          path[i][j] = tag[i][0];
        }
        if(j - tag[i][1] >= 0 && dp[i - 1][j - tag[i][1]]){
          dp[i][j] += dp[i - 1][j - tag[i][1]];
          path[i][j] = tag[i][1];
        }
      }
    }
    if(dp[cnt][p1] != 1){
      cout << "no\n";
    }else{
      for(int i=cnt,j=p1;j>0&&i>0;i--){
        if(path[i][j] == tag[i][0]){
          vis[i][0] = 1;
        }else{
          vis[i][1] = 1;
        }
        j -= path[i][j];
      }
      for(int i=1;i<=p1+p2;i++){
        if(vis[g[FIND(i)]][val[i]]){
          cout << i << '\n';
        }
      }
      cout << "end\n";
    }
  }
  return 0;
}

7. poj 1456 Supermarket

  • 贪心,把商品按照价格降序排列,逆序枚举每一天,看能否购买即可
  • 正确性证明,因为卖货全都是一天时间,卖个贵的显然要优于卖个便宜的,且可以等价替换
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;
struct st{
  int p, d;
  bool operator < (const st &B)const{
    return p > B.p || (p == B.p && d > B.d);
  }
};
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  while(cin >> n){
    vector<st> vs(n);
    int mx = -1;
    for(int i=0;i<n;i++){
      cin >> vs[i].p >> vs[i].d;
      mx = max(mx, vs[i].p);
    }sort(vs.begin(), vs.end());
    vector<int> vis(mx + 1);
    int ans = 0;
    for(int i=0;i<n;i++){
      for(int j=vs[i].d;j>0;j--){
        if(!vis[j]){
          ans += vs[i].p;
          vis[j] = 1;
          break;
        }
      }
    }
    cout << ans << '\n';
  }
  return 0;
}

8. poj 1733 Parity game

  • 如果区间 [ u , v ] [u,v] [u,v]内部有偶数个1,那么不妨设 v a l [ v ] − v a l [ u − 1 ] = 0 val[v]-val[u-1]=0 val[v]val[u1]=0,如果内部有奇数个1,那么 v a l [ v ] − v a l [ u − 1 ] = 1 val[v]-val[u-1]=1 val[v]val[u1]=1,那么显然是一个带权并查集,更新权值的过程中采用异或代替取模操作
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;

map<int, int> mp, val;

int FIND(int x){
  if(x == mp[x]) return x;
  if(x != mp[x]){
    int root = FIND(mp[x]);
    val[x] ^= val[mp[x]];
    mp[x] = root;
  }
  return mp[x];
}
void Merge(int u, int v, int d){
  int fu = FIND(u);
  int fv = FIND(v);
  if(fu != fv){
    val[fu] = val[u] ^ d ^ val[v];
    mp[fu] = fv;
  }
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> a(m), b(m), c(m);
  for(int i=0;i<m;i++){
    cin >> a[i] >> b[i];
    a[i] -= 1;
    mp[a[i]] = a[i];
    mp[b[i]] = b[i];
    string s;
    cin >> s;
    if(s[0] == 'e') c[i] = 0;
    else c[i] = 1;
  }
  int ans = 0;
  for(int i=0;i<m;i++){
    if(FIND(a[i]) != FIND(b[i])){
      Merge(a[i], b[i], c[i]);
    }else{
      if(val[a[i]] ^ val[b[i]] != c[i]) break;
    }
    ans += 1;
  }
  cout << ans;
  return 0;
}

9. poj1984 Navigation Nightmare

  • 显然是两个方向上的带权并查集即可,注意两个方向完全独立
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

typedef long long ll;
using namespace std;

ll ABS(ll x){
  return x < 0 ? -x : x;
}
const int N = 4e4 + 10;
int fax[N], fay[N];

ll xx[N], yy[N];
int FINDx(int x){
  if(x == fax[x]) return x;
  int root = FINDx(fax[x]);
  xx[x] += xx[fax[x]];
  return fax[x] = root;
}
int FINDy(int x){
  if(x == fay[x]) return x;
  int root = FINDy(fay[x]);
  yy[x] += yy[fay[x]];
  return fay[x] = root;
}
void Mergex(int u, int v, int d){
  int fu = FINDx(u);
  int fv = FINDx(v);
  if(fu != fv){
    xx[fu] = xx[v] + d - xx[u];
    fax[fu] = fv;
  }
}
void Mergey(int u, int v, int d){
  int fu = FINDy(u);
  int fv = FINDy(v);
  if(fu != fv){
    yy[fu] = yy[v] + d - yy[u];
    fay[fu] = fv;
  }
}
struct st{
  int id;
  int u, v;
  ll dis;
  char c;
};
struct ask{
  int u, v;
  int number;
  int id;
  bool operator < (const ask &B)const{
    return number < B.number;
  }
};
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  for(int i=1;i<=n;i++){
    fax[i] = i;
    fay[i] = i;
  }
  vector<st> vs(m);
  for(int i=0;i<m;i++){
    cin >> vs[i].u >> vs[i].v >> vs[i].dis >> vs[i].c;
    if(vs[i].u > vs[i].v){
      swap(vs[i].u, vs[i].v);
      if(vs[i].c == 'E') vs[i].c = 'W';
      else if(vs[i].c == 'W') vs[i].c = 'E';
      else if(vs[i].c == 'N') vs[i].c = 'S';
      else if(vs[i].c == 'S') vs[i].c = 'N';          
    }
    vs[i].id = i;
  }
  int q;
  cin >> q;
  vector<ask> que(q);
  for(int i=0;i<q;i++){
    cin >> que[i].u >> que[i].v >> que[i].number;
    que[i].id = i;
  }sort(que.begin(), que.end());
  int now = 0;
  vector<ll> ans(q);
  for(int i=0;i<q;i++){
    while(now < que[i].number){
      if(vs[now].c == 'E'){
        Mergex(vs[now].u, vs[now].v, vs[now].dis);
        Mergey(vs[now].u, vs[now].v, 0);
      }
      if(vs[now].c == 'W'){
        Mergex(vs[now].u, vs[now].v, -vs[now].dis);
        Mergey(vs[now].u, vs[now].v, 0);
      }
      if(vs[now].c == 'N'){
        Mergey(vs[now].u, vs[now].v, vs[now].dis);
        Mergex(vs[now].u, vs[now].v, 0);
      }
      if(vs[now].c == 'S'){
        Mergey(vs[now].u, vs[now].v, -vs[now].dis);
        Mergex(vs[now].u, vs[now].v, 0);
      }
      now += 1;
    }
    if(FINDx(que[i].u) == FINDx(que[i].v) && FINDy(que[i].u) == FINDy(que[i].v)){
      ans[que[i].id] = ABS(xx[que[i].u] - xx[que[i].v]) + ABS(yy[que[i].u] - yy[que[i].v]);
    }else{
      ans[que[i].id] = -1;
    }
  }
  for(int i=0;i<q;i++){
    cout << ans[i] << '\n';
  }
  return 0;
}

10. poj 2912 A Bug’s Life

  • [ u , v ] [u,v] [u,v]表示异性,问是否矛盾
  • 和食物链那题类似,只不过种类数变少了, 也可使用扩展域并查集,这里使用带权并查集,用权值表示属于哪一类
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;

const int N = 3e3;

int s[N];
int val[N];

int FIND(int x){
  if(x == s[x]) return x;
  int root = FIND(s[x]);
  val[x] ^= val[s[x]];
  return s[x] = root;
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int t;
  cin >> t;
  for(int kase=1;kase <= t;kase++){
    int n, m;
    cin >> n >> m;
    for(int j=1;j<=n;j++){
      s[j] = j;
      val[j] = 0;
    }
    bool ok = true;
    cout << "Scenario #" << kase << ":\n";
    for(int j=0;j<m;j++){
      int u, v;
      cin >> u >> v;
      int fu = FIND(u);
      int fv = FIND(v);
      if(fu != fv){
        s[fu] = fv;
        val[fu] = val[u] ^ val[v] ^ 1;
      }else{
        if(val[u] == val[v]) ok = false;
      }
    }
    if(ok) cout << "No suspicious bugs found!\n";
    else cout << "Suspicious bugs found!\n";
    cout << '\n';
  }
  return 0;
}

11. poj 2912 Rochambeau

  • 枚举每一个人可能成为裁判的情况
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;

struct st{
  int u, v;
  char c;
};
const int N = 505;
int fa[N], val[N];

int FIND(int x){
  if(x == fa[x]) return x;
  int root = FIND(fa[x]);
  val[x] = (val[x] + val[fa[x]]) % 3;
  return fa[x] = root;
}
bool Merge(int u, int v, int d){
  int fu = FIND(u);
  int fv = FIND(v);
  if(fu != fv){
    val[fv] = (val[u] + d + 3 - val[v]) % 3;
    fa[fv] = fu;
  }else{
    if((val[v] - val[u] + 3) % 3 != d) return false;
  }
  return true;
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  while(cin >> n >> m){
    int u, v;
    char c;
    vector<st> vs(m);
    for(int i=0;i<m;i++){
      cin >> vs[i].u >> vs[i].c >> vs[i].v;
    }
    int ans = 0;
    bool ok = true;
    int tot = 0;
    int line = 0;
    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        fa[j] = j;
        val[j] = 0;
      }
      ok = true;
      for(int j=0;j<m;j++){
        int d = 0;
        if(vs[j].u == i || vs[j].v == i) continue;
        if(vs[j].c == '=') d = 0;
        if(vs[j].c == '>') d = 1;
        if(vs[j].c == '<') d = 2;
        if(!Merge(vs[j].u, vs[j].v, d)){
          ok = false;
          line = max(line, j + 1);
          break;
        }
      }
      if(ok){
        tot += 1;
        ans = i;
      }
    }
    if(tot > 1){
      cout << "Can not determine\n";
    }else if(!tot){
      cout << "Impossible\n";
    }else{
      cout << "Player " << ans << " can be determined to be the judge after " << line << " lines\n";
    }
  }
  return 0;
}

12. ZOJ-3261 Connections in Galaxy War

  • 离线倒着处理?以前做的好像挺常规的
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;


const int N = 1e5 + 100;

int fa[N], val[N], p[N];

int FIND(int x){
  if(x == fa[x]) return x;
  int root = FIND(fa[x]);
  val[x] = max(val[x], val[fa[x]]);
  return fa[x] = root;
}
void Merge(int u, int v){
  int fu = FIND(u);
  int fv = FIND(v);
  if(fu != fv){
    if(val[fu] == val[fv]){
      if(fu > fv) swap(fu, fv);
      fa[fv] = fu;
    }else if(val[fu] > val[fv]){
      fa[fv] = fu;
    }else{
      fa[fu] = fv;
    }
  }
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  bool f = false;
  while(cin >> n){
    if(f) cout << '\n';
    f = true;
    for(int i=0;i<n;i++){
      cin >> p[i];
      val[i] = p[i];
      fa[i] = i;
    }
    int m;
    cin >> m;
    vector<pair<int, int> > vs(m);
    for(int i=0;i<m;i++){
      cin >> vs[i].first >> vs[i].second;
      if(vs[i].first > vs[i].second) swap(vs[i].first, vs[i].second);
    }
    int q;
    cin >> q;
    vector<vector<int> > operation(q);
    set<pair<int, int> > st;
    for(int i=0;i<q;i++){
      string s;
      int u, v;
      cin >> s;
      if(s == "query"){
        cin >> u;
        operation[i].push_back(u);
      }else{
        cin >> u >> v;
        if(u > v) swap(u, v);
        operation[i].push_back(u);
        operation[i].push_back(v);
        st.insert(make_pair(u, v));
      }
    }
    for(int i=0;i<m;i++){
      if(!st.count({vs[i].first, vs[i].second})){
        Merge(vs[i].first, vs[i].second);
      }
    }
    vector<int> ans;
    for(int i=q-1;i>=0;i--){
      if((int)operation[i].size() > 1){
        int u = operation[i][0];
        int v = operation[i][1];
        Merge(u, v);
      }else{
        int root = FIND(operation[i][0]);
        if(val[root] > p[operation[i][0]]){
          ans.push_back(root);
        }else{
          ans.push_back(-1);
        }
      }
    }
    reverse(ans.begin(), ans.end());
    for(auto i : ans){
      cout << i << '\n';
    }
  }
  return 0;
}

13. hdu 1272 小希的迷宫

  • 注意要求输出的是权值最大,编号最小的,所以带权并查集维护的祖先节点应该满足这两条,然后常规思路离线处理即可
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;


const int N = 1e5 + 100;

int fa[N], val[N], p[N];

int FIND(int x){
  if(x == fa[x]) return x;
  int root = FIND(fa[x]);
  val[x] = max(val[x], val[fa[x]]);
  return fa[x] = root;
}
void Merge(int u, int v){
  int fu = FIND(u);
  int fv = FIND(v);
  if(fu != fv){
    if(val[fu] == val[fv]){
      if(fu > fv) swap(fu, fv);
      fa[fv] = fu;
    }else if(val[fu] > val[fv]){
      fa[fv] = fu;
    }else{
      fa[fu] = fv;
    }
  }
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  bool f = false;
  while(cin >> n){
    if(f) cout << '\n';
    f = true;
    for(int i=0;i<n;i++){
      cin >> p[i];
      val[i] = p[i];
      fa[i] = i;
    }
    int m;
    cin >> m;
    vector<pair<int, int> > vs(m);
    for(int i=0;i<m;i++){
      cin >> vs[i].first >> vs[i].second;
      if(vs[i].first > vs[i].second) swap(vs[i].first, vs[i].second);
    }
    int q;
    cin >> q;
    vector<vector<int> > operation(q);
    set<pair<int, int> > st;
    for(int i=0;i<q;i++){
      string s;
      int u, v;
      cin >> s;
      if(s == "query"){
        cin >> u;
        operation[i].push_back(u);
      }else{
        cin >> u >> v;
        if(u > v) swap(u, v);
        operation[i].push_back(u);
        operation[i].push_back(v);
        st.insert(make_pair(u, v));
      }
    }
    for(int i=0;i<m;i++){
      if(!st.count({vs[i].first, vs[i].second})){
        Merge(vs[i].first, vs[i].second);
      }
    }
    vector<int> ans;
    for(int i=q-1;i>=0;i--){
      if((int)operation[i].size() > 1){
        int u = operation[i][0];
        int v = operation[i][1];
        Merge(u, v);
      }else{
        int root = FIND(operation[i][0]);
        if(val[root] > p[operation[i][0]]){
          ans.push_back(root);
        }else{
          ans.push_back(-1);
        }
      }
    }
    reverse(ans.begin(), ans.end());
    for(auto i : ans){
      cout << i << '\n';
    }
  }
  return 0;
}

14. poj 1308 Is It A Tree?

  • 如果输入的点不能构成一个连通块,或者连边之后出现环就说明不是树
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>

using namespace std;

const int N = 2e5 + 5;
int s[N + 20];
int FIND(int x){
  return x == s[x] ? x : s[x] = FIND(s[x]);
}
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int u, v;
  vector<int> vs;
  for(int i=1;i<=N;i++) s[i] = i;
  int mx = 0;
  int kase = 1;
  bool yes = true;
  while(cin >> u >> v){
    if(u == -1 && v == -1) break;
    mx = max(max(u, v), mx);
    while(true){
      if(u == 0 && v == 0){
        sort(vs.begin(), vs.end());
        vs.erase(unique(vs.begin(), vs.end()), vs.end());
        for(int i=1;i<(int)vs.size();i++){
          if(FIND(vs[i]) != FIND(vs[i - 1])) yes = false;
        }
        if(yes){
          cout << "Case " << kase << " is a tree.\n";
        }else{
          cout << "Case " << kase << " is not a tree.\n";
        }
        for(int i=1;i<=mx;i++) s[i] = i;
        kase += 1;
        mx = 0;
        yes = true;
        vs.clear();
        break;
      }
      vs.push_back(u);
      vs.push_back(v);
      mx = max(mx, max(u, v));
      int fu = FIND(u);
      int fv = FIND(v);
      if(fu == fv) yes = false;
      s[fu] = fv;
      cin >> u >> v;
    }
  }
  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/125909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MYSQL IN EXISTS LEFT JOIN 结果不同的问题?

随着问问题的同学越来越多&#xff0c;公众号内部私信回答问题已经很困难了&#xff0c;所以建立了一个群&#xff0c;关于各种数据库的问题都可以&#xff0c;目前主要是 POSTGRESQL, MYSQL ,MONGODB ,POLARDB ,REDIS 等&#xff0c;期待你的加入&#xff0c;加群请添加微信li…

智慧园区建设面临挑战,该如何应对?

随着全球物联网、移动互联网、云计算等新一轮信息技术的迅速发展和深入应用&#xff0c;“智慧园区”建设已成为发展趋势。近年来&#xff0c;我国的产业园区也向着智慧化、创新化、科技化转变。中国经济正在进入转型升级的关键时期&#xff0c;各地产业竞争态势越发激烈。可以…

ClickHouse 大数据量的迁移方式

关于Clickhouse 备份方式&#xff0c;其官方网站上就提供了多种备份方式可以参考&#xff0c;不同的业务需求有不同的使用场景&#xff0c;需要使用不同的备份方式&#xff0c;不存在一个通用的解决方案可以应对各种情况下的ClickHouse备份和恢复。今天这个文字&#xff0c;我们…

Qt+第三方库开发遇到的坑---kalrry

Qt依赖UG库开发遇到的坑---kalrry一、依赖引入坑二、Qt在Debug时报错1、编译器是 **MSVC** 还是 **MinGW**2、编译器 32位 还是 64位三、QtMSVC编译后中文乱码四、不能将const char*类型的值分配到const* 类型的实体五、debug编译后再发布程序无法运行六、Qt 环境配置提示警告警…

Spring @Transactional注解事务六大失效场景

Transactional事务失效场景1&#xff1a;注解在非public修饰的方法上。 原因&#xff1a;Spring强制的要求。 代码示例&#xff1a; Transactionalprivate void createOrder(){} Transactional事务失效场景2&#xff1a;注解在被final关键字修饰的方法上。 原因&#xff1a;Spr…

推荐一款好用的设备维护管理系统,你用过了吗

设备维护管理系统层出不穷&#xff0c;找到一款好用的适配的&#xff0c;也要花费大量的时间去挑选&#xff01; 对于企业来说&#xff0c;一个好的设备管理系统应该能够&#xff1a; 1. 适应企业高度场景化的设备管理工作&#xff0c;覆盖设备的采购、常规检查、养护、添装、…

“三刷”牛客网844道Java题目,易错知识点总结,带你清扫Java基础面试障碍

目录 前言 1、子类通过哪些办法&#xff0c;可以调用继承自父类的方法&#xff1f; 2、volatile、Lock、transient 哪个关键字不能用来处理线程安全 3、Hashtable 和 HashMap 的区别是&#xff1f;&#xff08;容易忽略的两点&#xff09; 4、如何声明了一个适合于创建50个字…

flask框架实现文件下载接口

方式一&#xff1a; app.route("/download1") def download():# return send_file(test.exe, as_attachmentTrue)return send_file(2.jpg)# return send_file(1.mp3)如果不加as_attachment参数&#xff0c;则会向浏览器发送文件&#xff0c;比如发送一张图片&#x…

Revit技巧:快速隔离一个小构件,拉伸屋顶转折处连接

一、Revit中如何快速单独隔离一个小构件 今天跟大家分享的是一个快速隔离的小技巧&#xff0c;你可以理解为快速用剖面框拉成你需要的构件区域。我就举个例子让大家简单容易理解&#xff0c;如图1所示&#xff0c;假设我只需要编辑那个墙的装饰&#xff0c;但又需要用剖面框&am…

704二分查找法--搜索区间

二分查找法–搜索区间的深入理解 二分查找法是算法学习中很基础的算法&#xff0c;但是其也是很重要的算法&#xff0c;将二分查找法搞明白对后续算法的学习有着事半功倍的作用。 本体难点&#xff1a;二分搜索区间的判断 搜索区间 [left,right] int search(vector<int>…

026_SS_MoFusion A Framework for Denoising-Diffusion-based Motion Synthesis

MoFusion: A Framework for Denoising-Diffusion-based Motion Synthesis 本文提出了一种利用diffusion生成人体motion的方法。这种方法可以将音频和文本作为条件。 损失函数 对于diffusion的损失中&#xff0c;加入了运动损失。 其中第一项 LdaL_{da}Lda​ 是原始的diffusio…

微信公众号如何接入ChatGPT机器人

不难&#xff0c;代码总共也就25行&#xff0c;大致逻辑如下。 总共分为是下面两步 文章目录在云服务器上部署自定义消息处理服务微信公众号配置自己的消息处理服务器在云服务器上部署自定义消息处理服务 这里需要我们自定义来处理用户发送过来的消息 首先导入werobot&#x…

Linux操作系统实验2——进程描述

实验要求&#xff1a; 1.查看task_struct的结构&#xff0c;找到其中的pid&#xff0c;state&#xff0c;prio&#xff0c;parent pid字段 2.在task_struct结构中找到vma相关字段&#xff0c;vm_start,vm_end,vm_next 3.打印指定pid的基本信息&#xff0c;包括基本信息及VMA内存…

分组卷积与dw卷积

分组卷积&#xff08;Group Convolution&#xff09; 分组卷积在ResNext中用到了 首先必须明确&#xff1a; 常规卷积&#xff08;Convolution&#xff09;的参数量是&#xff1a; K*K*C_in*n K是卷积核大小&#xff0c;C_in是input的channel数&#xff0c;n是卷积核个数(outp…

共享模型之管程(一)

1.共享带来的问题 1.1.线程安全问题 例如: 两个线程对初始值为0的静态变量一个做自增,一个做自减,各做5000次,结果是0吗? Slf4j public class TestThread {//静态共享变量static int counter 0;public static void main(String[] args) throws InterruptedException {Threa…

【Axure教程】拖动排序——扣款顺序

随着移动支付的发展&#xff0c;移动支付的途径和方式也越来越多&#xff0c;常见的有钱包余额支付、支付宝支付、微信支付、银行卡支付……随着绑定的账户越来越多&#xff0c;我们需要一个设置扣款顺序的功能页面。 所以今天作者就教大家如果做一个拖动排序的扣款顺序的原型…

机器学习的4种经典模型总结

机器学习&#xff08;Machine Learning&#xff09;是人工智能的一个分支&#xff0c;也是人工智能的一种实现方法。机器学习的核心是“使用算法解析数据&#xff0c;从中学习&#xff0c;然后对新数据做出决定或预测”&#xff0c;机器学习的概念就是通过输入海量训练数据对模…

【财务】FMS财务管理系统---质保金与预付款

在FMS财务管理系统中&#xff0c;如何对质保金和预付款进行管理&#xff0c;笔者做了详细的业务流程拆解。 上一篇主要说了财务应收管理&#xff0c;有一些朋友留言提出了很多建议&#xff0c;在这里必须谢谢。 关于应收分为ToC与ToB两部分&#xff0c;每一部分都与前端业务系…

新一代自动出价范式:在线强化学习SORL框架

丨目录&#xff1a; 摘要 动机&#xff1a;在离线不一致问题 问题建模 方法&#xff1a;SORL框架 实验结果 总结 关于我们 参考文献▐ 摘要近年来&#xff0c;自动出价已成为广告主提升投放效果的重要方式&#xff0c;在真实广告系统&#xff08;RAS&#xff09;中&#xff0c;…

C++ 数学与算法系列之高斯消元法求解线性方程组

1. 前言 什么是消元法&#xff1f; 消元法是指将多个方程式组成的方程组中的若干个变量通过有限次地变换&#xff0c;消去方程式中的变量&#xff0c;通过简化方程式&#xff0c;从而获取结果的一种解题方法。 消元法主要有代入消元法、加减消元法、整体消元法、换元消元法、…