[APIO2020]交换城市
description
solution
如果 u , v u,v u,v存在于一条链上(只有两个点度数为 1 1 1其余点度数为 2 2 2)则无解,否则必有解
如图,不管是哪个点度数 > 2 >2 >2,都可以有解
以蓝色为例,第二个红点右移到蓝色右边,第一个红点走进蓝色,第二个红点走到第一个红点开始位置,第一个红点出来回到第二个红点开始位置
因此本题只是在kruskal
重构树(每次新建一个点,把两个点连在新点下面当儿子,新点点权即为原两点的边权)的基础上多了一个链判断的维护
不需要用启发式合并,只需要判断siz[u]=cnt[u][1]+cnt[u][2]&&cnt[u][1]==2
code
#include "swap.h"
#include <bits/stdc++.h>
using namespace std;
#define maxn 300005
struct node {
int u, v, w;
node(){}
node( int U, int V, int W ) {
u = U, v = V, w = W;
}
}edge[maxn];
vector < int > G[maxn];
int n, m, ip;
int MS[maxn], d[maxn], val[maxn], siz[maxn], g[maxn], dep[maxn];
int f[maxn][20], cnt[maxn][3];
bool cmp ( node x, node y ) {
return x.w < y.w;
}
int find( int x ) {
return x == MS[x] ? x : MS[x] = find( MS[x] );
}
void dfs( int u, int fa ) {
f[u][0] = fa, dep[u] = dep[fa] + 1;
for( int i = 1;i < 20;i ++ )
f[u][i] = f[f[u][i - 1]][i - 1];
if( cnt[u][1] == 2 && cnt[u][1] + cnt[u][2] == siz[u] ) g[u] = g[fa];
else g[u] = u;
for( int i = 0;i < ( int )G[u].size();i ++ ) {
int v = G[u][i];
if( v == fa ) continue;
else dfs( v, u );
}
}
void modify( int x, int v ) {
if( 1 <= d[x] && d[x] <= 2 ) cnt[find( x )][d[x]] += v;
}
void kruskal() {
sort( edge + 1, edge + m + 1, cmp );
for( int i = 1;i <= n;i ++ ) MS[i] = i, siz[i] = 1;
ip = n;
for( int i = 1;i <= m;i ++ ) {
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
int fu = find( u ), fv = find( v );
if( fu ^ fv ) {
++ ip;
cnt[ip][1] = cnt[fu][1] + cnt[fv][1];
cnt[ip][2] = cnt[fu][2] + cnt[fv][2];
siz[ip] = siz[fu] + siz[fv];
MS[fu] = ip, MS[fv] = ip;
val[ip] = w;
MS[ip] = ip;
G[ip].push_back( fu );
G[ip].push_back( fv );
}
else if( val[fu] != w ) {
++ ip;
cnt[ip][1] = cnt[fu][1];
cnt[ip][2] = cnt[fu][2];
siz[ip] = siz[fu];
MS[fu] = ip;
MS[ip] = ip;
val[ip] = w;
G[ip].push_back( fu );
}
modify( u, -1 );
modify( v, -1 );
d[u] ++;
d[v] ++;
modify( u, 1 );
modify( v, 1 );
}
dfs( ip, 0 );
}
int get_lca( int u, int v ) {
if( dep[u] < dep[v] ) swap( u, v );
for( int i = 19;~ i;i -- )
if( dep[f[u][i]] >= dep[v] )
u = f[u][i];
if( u == v ) return u;
for( int i = 19;~ i;i -- )
if( f[u][i] != f[v][i] )
u = f[u][i], v = f[v][i];
return f[u][0];
}
void init( int N, int M, vector < int > U, vector < int > V, vector < int > W ) {
n = N, m = M;
for( int i = 0;i < m;i ++ )
edge[i + 1] = node( U[i] + 1, V[i] + 1, W[i] );
kruskal();
}
int getMinimumFuelCapacity( int x, int y ) {
x ++, y ++;
int lca = get_lca( x, y );
if( ! g[lca] ) return -1;
else return val[g[lca]];
}
完全不能调试的交互题!!!