树/图上问题

树/图上问题

P3398 仓鼠找 sugar

两组路径 (u,v) (p,q) 相交 当且仅当一组路径的 lca 在第二组路径上 那么判断两次即可

#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 提高组] 信息传递

虽然是黄题 但是是一道好题

相当于是求图上最小环

tarjan 可以通过 但是不具有普适性

我们可以用并查集来维护

对于每一条边 我们加入并查集 如果两端点不联通 那么将两个端点连在同一个集合中 否则统计两个点到根节点的路径之和 +1 并更新答案

这个更新路径的方法的正确性在于:我们的 dis 一定是有值的(值为到祖先节点的距离) 那么我们只需要累加父亲节点的贡献即可

#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 词链

搜索题 正常搜索会 T 我们考虑将原图能连边的两个点连边 转化为有向图来处理欧拉回路

每加进来一个单词 将它的首字母的 rd 和末尾字母的 cd 自增

将所有单词排序 如果这个单词首字母的 rd 等于 这个单词首字母的 cd+1 说明这个点可以成为起点 从这个单词开始搜索即可

如果上面的条件都无法满足 我们直接从 1 开始搜索即可 如果还是无法搜到 输出无解即可

#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 的旅行路线

思路两分钟 代码两小时的典范

显然我们建边跑 floyd 就能过()

建边一开始用结构体存每一个城市 代码难度太大导致重构

id 来判断每一个点的位置显然优秀很多

坑点:只给了三个机场位置 需要用矩形坐标公式来算另外一个

 #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;
}

posted @   Echo_Long  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示