window.cnblogsConfig = {//可以放多张照片,应该是在每一个博文上面的图片,如果是多张的话,那么就随机换的。 homeTopImg: [ "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png", "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png" ], }

CF320B解题报告

题意

有一些区间,当且仅当一个区间包含另一个区间的起点或终点时,这两个区间可以互相到达。

需要处理两种操作:

  • 添加一个区间,保证这个区间的长度严格大于之前区间的长度。
  • 询问一个区间是否能到达另一个区间。

分析

不难看出可以建图然后 dfs 一遍看起点能不能到达终点。

对于添加操作,相当于建图,如果区间 \(x\) 能到达区间 \(y\)(满足题面上的条件),那么就连一条边,建反边同理(可以从 \(y\) 转移到 \(x\))。

对于查询操作,直接 dfs 看能不能从 \(a\) 区间到达 \(b\) 区间,dfs 部分不再赘述,最后输出。

代码

#include <bits/stdc++.h>
using namespace std;

int n, len, flag;
int l[105], r[105], vis[105];
vector<int> g[105];

void dfs(int x, int ex){
	if (flag) return ;
	if (x == ex){//走到了
		flag = 1;
		return ;
	}
	vis[x] = 1;
	for (int i = 0; i < g[x].size(); i++){
		int v = g[x][i];
		if (vis[v] == 0) dfs(v, ex);
	}
}

int main(){
	cin >> n;
	for (int i = 1, opt, x, y; i <= n; i++){
		cin >> opt >> x >> y;
		if (opt == 1){
			l[++len] = x, r[len] = y;
			for (int i = 1; i < len; i++){//这里只需要遍历已经添加过的边,后面加进来的边也会再来一次,建反边时相当于从这里建了一条正边
				if ((l[i] < l[len] && l[len] < r[i]) || (l[i] < r[len] && r[len] < r[i])) g[len].push_back(i);//满足条件建边
				if ((l[len] < l[i] && l[i] < r[len]) || (l[len] < r[i] && r[i] < r[len])) g[i].push_back(len);//建反向边
			} 
		}
		else{
			memset(vis, 0, sizeof(vis));//记录每个点是否走过
			flag = 0;
			dfs(x, y);//看能不能从x移动到y
			if (flag == 1) cout << "YES\n";
			else cout << "NO\n";
		}
	}
	return 0;
}
posted @ 2024-01-18 07:45  CCF_IOI  阅读(35)  评论(0)    收藏  举报