• 【ybt高效进阶 21162】双面扑克(图论模型)(线段树)(并查集)


    双面扑克

    题目链接:ybt高效进阶 21162

    题目大意

    给你 n 个牌,正面反面都有数,多次询问,每次问你能不能凑出 l~r 的顺子。

    思路

    考虑建立图论模型。

    如果一个牌的正反面分别是 (x,y),就把 (x,y) 连一条边。
    然后考虑怎样是可以凑出顺子的。

    我们可以对于考虑每个数在图论模型中的连通块。
    如果那个连通块不是所有点都是在顺子中,那你必然可以一条连着顺子中的数和顺子外的数选顺子内的,然后就不断的往外扩展。
    那同一个道理,就算整个连通块都是顺子中的,只要它的边数大于等于它的点数,也是可以的。

    那似乎很多情况都可以,那什么情况凑不出呢?
    那就是这个连通块的点都是数,而且这个连通块是一棵树。
    那我们可以用并查集的简单维护找到是树的连通块。

    那要怎么快速判断顺子中是否包含了这些树呢?
    考虑是数字,那如果这个顺子包含了这个树,这个数的点分别是 (a_1,a_2,...,a_m)
    那这个顺子一定有这么一个部分:(min{a_1,a_2,..,a_m}simmax{a_1,a_2,...,a_n})

    那我们可以把树的最大点和最小点找出来(我是直接顺手在并查集中维护),然后就变成了线段覆盖问题,离线然后线段树搞就可以啦。
    (注意如果有覆盖到输出的是 No,没有才是 Yes,因为你是看是否会无法凑出)

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    struct tree {
    	int l, r, pl;
    }a[100001], q[100001];
    int n, k, x, y, fa[100001], an;
    int maxn[100001], minn[100001], qq;
    bool ntr[100001], ans[100001];
    
    bool cmp(tree x, tree y) {
    	if (x.r != y.r) return x.r < y.r;
    	return x.l < y.l;
    }
    
    int find(int now) {
    	if (fa[now] == now) return now;
    	return fa[now] = find(fa[now]);
    }
    
    void work(int x, int y) {//用并查集来判断是否有树
    	int X = find(x), Y = find(y);
    	if (X == Y) ntr[X] = 1;
    	fa[X] = Y; ntr[Y] |= ntr[X];
    	maxn[Y] = max(maxn[Y], maxn[X]);
    	minn[Y] = min(minn[Y], minn[X]);
    }
    
    struct Tree {//离线+线段树解决线段覆盖问题
    	int a[400001];
    	
    	void up(int now) {
    		a[now] = a[now << 1] + a[now << 1 | 1]; 
    	}
    	
    	void insert(int now, int l, int r, int pl) {
    		if (l == r) {
    			a[now]++;
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		if (pl <= mid) insert(now << 1, l, mid, pl);
    			else insert(now << 1 | 1, mid + 1, r, pl);
    		up(now);
    	}
    	
    	int query(int now, int l, int r, int L, int R) {
    		if (L <= l && r <= R) return a[now];
    		int mid = (l + r) >> 1, re = 0;
    		if (L <= mid) re += query(now << 1, l, mid, L, R);
    		if (mid < R) re += query(now << 1 | 1, mid + 1, r, L, R);
    		return re;
    	}
    }T;
    
    int main() {
    //	freopen("yy.in", "r", stdin);
    //	freopen("yy.out", "w", stdout);
    	
    	scanf("%d %d", &n, &k);
    	
    	for (int i = 1; i <= n; i++) fa[i] = maxn[i] = minn[i] = i;
    	
    	for (int i = 1; i <= k; i++) {
    		scanf("%d %d", &x, &y);
    		work(x, y);
    	}
    	
    	for (int i = 1; i <= n; i++)
    		if (!ntr[i] && find(i) == i) {
    			a[++an] = (tree){minn[i], maxn[i], -1};
    	}
    	
    	scanf("%d", &qq);
    	for (int i = 1; i <= qq; i++) {
    		scanf("%d %d", &q[i].l, &q[i].r);
    		q[i].pl = i;
    	}
    	
    	sort(a + 1, a + an + 1, cmp);
    	sort(q + 1, q + qq + 1, cmp);
    	
    	int anow = 1, qnow = 1;
    	for (int i = 1; i <= n; i++) {
    		while (anow <= an && a[anow].r == i) {
    			T.insert(1, 1, n, a[anow].l);
    			anow++;
    		}
    		while (qnow <= qq && q[qnow].r == i) {
    			if (T.query(1, 1, n, q[qnow].l, n)) ans[q[qnow].pl] = 1;
    			qnow++;
    		}
    	}
    	
    	for (int i = 1; i <= qq; i++)
    		if (ans[i]) printf("No
    ");
    			else printf("Yes
    ");
    	
    	return 0;
    } 
    
  • 相关阅读:
    python爬虫之Anaconda安装
    python爬虫之scrapy安装(一)
    python爬虫之redis环境简单部署
    python爬虫之Phantomjs安装和使用
    python爬虫之win7Mongod安装使用
    python爬虫之PyQuery的基本使用
    python爬虫之xpath的基本使用
    python爬虫之git的使用(windows下pycharm使用)
    Sass教程
    Vue.js教程—1.介绍和安装
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_GXJJ_21162.html
Copyright © 2020-2023  润新知