[APIO2020]交换城市
description
solution
如果u,vu,vu,v存在于一条链上(只有两个点度数为111其余点度数为222)则无解,否则必有解
如图,不管是哪个点度数>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]];
}
完全不能调试的交互题!!!