树/图上问题
树/图上问题
P3398 仓鼠找 sugar
两组路径
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 1e5 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , q;
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
int sz[N] , son[N] , dep[N] , fa[N];
int timer , rev[N] , pos[N] , top[N];
struct LCA
{
void dfs1 ( int u , int ff )
{
dep[u] = dep[ff] + 1 , fa[u] = ff , sz[u] = 1;
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs1 ( v , u );
sz[u] += sz[v];
if ( sz[son[u]] < sz[v] ) son[u] = v;
}
}
void dfs2 ( int u , int tp )
{
top[u] = tp , pos[u] = ++timer , rev[timer] = u;
if ( son[u] ) dfs2 ( son[u] , tp );
for ( auto v : e[u] ) if ( v != fa[u] && v != son[u] ) dfs2 ( v , v );
}
int lca ( int u , int v )
{
while ( top[u] != top[v] )
{
if ( dep[top[u]] < dep[top[v]] ) swap ( u , v );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u , v );
return v;
}
}L;
int dis ( int u , int v ) { return dep[u] + dep[v] - 2 * dep[L.lca(u,v)]; }
int check ( int a , int b , int c , int d ) { return dis ( c , L.lca ( a , b ) ) + dis ( d , L.lca ( a , b ) ) == dis ( c , d ); }
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , q = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
L.dfs1 ( 1 , 0 ) , L.dfs2 ( 1 , 1 );
for ( int i = 1 ; i <= q ; i ++ )
{
int a = read() , b = read() , c = read() , d = read();
if ( check ( a , b , c , d ) || check ( c , d , a , b ) ) cout << "Y" << endl;
else cout << "N" << endl;
}
return 0;
}
P8287 「DAOI R1」Flame
考虑二分答案 每次将所有符合条件的边加入 同时用并查集维护连通性 判断有没有环即可
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int inf = 0x3f3f3f3f;
const int N = 2e6 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , k , dis[N] , fa[N] , vis[N] , u[N] , v[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
struct Dsu
{
void init() { for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i; }
int find ( int x ) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void merge ( int u , int v ) { int fu = find(u) , fv = find(v); fa[fu] = fv; }
}D;
int check ( int lim )
{
D.init();
for ( int i = 1 ; i <= m ; i ++ ) if ( dis[u[i]] <= lim && dis[v[i]] <= lim )
{
if ( D.find(u[i]) == D.find(v[i]) ) return 1;
else D.merge ( u[i] , v[i] );
}
return 0;
}
int head = 1 , tail , q[N*10];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , k = read();
for ( int i = 1 ; i <= m ; i ++ ) u[i] = read() , v[i] = read() , add ( u[i] , v[i] ) , add ( v[i] , u[i] );
memset ( dis , inf , sizeof dis );
for ( int i = 1 ; i <= k ; i ++ ) q[++tail] = read() , dis[q[tail]] = 0;
while ( head <= tail )
{
int u = q[head++]; vis[u] = 1;
for ( auto v : e[u] )
if ( !vis[v] )
{
if ( dis[v] > dis[u] + 1 )
{
dis[v] = dis[u] + 1;
q[++tail] = v;
}
}
}
int l = 0 , r = n;
if ( !check(n) ) return cout << "Poor D!" << endl , 0;
while ( l <= r )
{
if ( check(mid) ) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
[P2661 NOIP2015 提高组] 信息传递
虽然是黄题 但是是一道好题
相当于是求图上最小环
我们可以用并查集来维护
对于每一条边 我们加入并查集 如果两端点不联通 那么将两个端点连在同一个集合中 否则统计两个点到根节点的路径之和
这个更新路径的方法的正确性在于:我们的
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans = inf , dis[N] , fa[N];
int find ( int x )
{
if ( fa[x] != x )
{
int temp = find(fa[x]);
dis[x] += dis[fa[x]];//注意:我们的dis一定是有值的(值为到祖先节点的距离) 那么我们只需要累加父亲节点的贡献即可
fa[x] = temp;
}
return fa[x];
}
void check ( int u , int v )
{
int fu = find(u) , fv = find(v);
if ( fu != fv ) { fa[fu] = fv , dis[fu] = dis[v] + 1; }
else ans = min ( ans , dis[u] + dis[v] + 1 );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i;
for ( int i = 1 ; i <= n ; i ++ )
{
int to = read();
check ( i , to );
}
cout << ans << endl;
return 0;
}
P1127 词链
搜索题 正常搜索会
每加进来一个单词 将它的首字母的
将所有单词排序 如果这个单词首字母的
如果上面的条件都无法满足 我们直接从
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int inf = 0x3f3f3f3f;
const int N = 5e3 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , st , vis[N] , in[N] , out[N];
string s[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , string now , int cnt )
{
if ( cnt == n )
{
now.pop_back();
cout << now << endl;
exit(0);
}
for ( auto v : e[u] )
if ( !vis[v] )
{
vis[v] = 1;
dfs ( v , now + s[v] + '.' , cnt + 1 );
vis[v] = 0;
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) cin >> s[i] , ++ in[s[i][0]] , ++ out[s[i][s[i].size()-1]];
sort ( s + 1 , s + n + 1 );
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
if ( i != j && s[i][s[i].size()-1] == s[j][0] )
add ( i , j );
for ( int i = 1 ; i <= n ; i ++ )
if ( in[s[i][0]] == out[s[i][0]] + 1 )
{
vis[i] = 1;
dfs ( i , s[i] + '.' , 1 );
vis[i] = 0;
}
st = 1;
vis[st] = 1;
dfs ( st , s[st] + '.' , 1 );
vis[st] = 0;
cout << "***" << endl;
return 0;
}
P1027 [NOIP2001 提高组] Car 的旅行路线
思路两分钟 代码两小时的典范
显然我们建边跑
建边一开始用结构体存每一个城市 代码难度太大导致重构
用
坑点:只给了三个机场位置 需要用矩形坐标公式来算另外一个
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const double inf = 2e9 + 5;
const int N = 400 + 5;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , s , t;
double f[N][N] , plane , x[N] , y[N] , train[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
int id ( int i , int j ) { return ( i - 1 ) * 4 + j; }
double dis ( int i , int j ) { return sqrt ( ( x[i] - x[j] ) * ( x[i] - x[j] ) + ( y[i] - y[j] ) * ( y[i] - y[j] ) ); }
void init() { for ( int i = 1 ; i < N ; i ++ ) for ( int j = 1 ; j < N ; j ++ ) f[i][j] = inf; }
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , plane = read() , s = read() , t = read();
init();
if ( s == t ) { cout << "0.0" << endl; continue; }
for ( int i = 1 ; i <= n ; i ++ )
{
for ( int j = 1 ; j <= 3 ; j ++ ) x[id(i,j)] = read() , y[id(i,j)] = read();
int dis12 = ( x[id(i,2)] - x[id(i,1)] ) * ( x[id(i,2)] - x[id(i,1)] ) + ( y[id(i,2)] - y[id(i,1)] ) * ( y[id(i,2)] - y[id(i,1)] );
int dis23 = ( x[id(i,3)] - x[id(i,2)] ) * ( x[id(i,3)] - x[id(i,2)] ) + ( y[id(i,3)] - y[id(i,2)] ) * ( y[id(i,3)] - y[id(i,2)] );
int dis13 = ( x[id(i,3)] - x[id(i,1)] ) * ( x[id(i,3)] - x[id(i,1)] ) + ( y[id(i,3)] - y[id(i,1)] ) * ( y[id(i,3)] - y[id(i,1)] );
if ( dis23 + dis13 == dis12 ) x[id(i,4)] = x[id(i,1)] + x[id(i,2)] - x[id(i,3)] , y[id(i,4)] = y[id(i,1)] + y[id(i,2)] - y[id(i,3)];//12对角线
if ( dis12 + dis23 == dis13 ) x[id(i,4)] = x[id(i,1)] + x[id(i,3)] - x[id(i,2)] , y[id(i,4)] = y[id(i,1)] + y[id(i,3)] - y[id(i,2)];//13对角线
if ( dis13 + dis12 == dis23 ) x[id(i,4)] = x[id(i,2)] + x[id(i,3)] - x[id(i,1)] , y[id(i,4)] = y[id(i,2)] + y[id(i,3)] - y[id(i,1)];//23对角线
train[i] = read();
}
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= 4 ; j ++ )
for ( int k = 1 ; k <= 4 ; k ++ )
if ( j != k ) f[id(i,j)][id(i,k)] = f[id(i,k)][id(i,j)] = dis ( id(i,j) , id(i,k) ) * train[i];
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
if ( i != j )
{
for ( int k = 1 ; k <= 4 ; k ++ )
for ( int l = 1 ; l <= 4 ; l ++ )
f[id(i,k)][id(j,l)] = f[id(j,l)][id(i,k)] = dis ( id(i,k) , id(j,l) ) * plane;
}
for ( int i = 1 ; i <= n * 4 ; i ++ ) f[i][i] = 0;
for ( int k = 1 ; k <= n * 4 ; k ++ )
for ( int i = 1 ; i <= n * 4 ; i ++ )
for ( int j = 1 ; j <= n * 4 ; j ++ )
f[i][j] = min ( f[i][k] + f[k][j] , f[i][j] );
// for ( int i = 1 ; i <= n * 4 ; i ++ , cout.put(endl) )
// for ( int j = 1 ; j <= n * 4 ; j ++ )
// cout << f[i][j] << ' ';
double minn = inf;
for ( int i = id(s,1) ; i <= id(s,4) ; i ++ )
for ( int j = id(t,1) ; j <= id(t,4) ; j ++ )
minn = min ( minn , f[i][j] );
cout << fixed << setprecision(1) << minn << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!