zoukankan      html  css  js  c++  java
  • CF 901C Bipartite Segments

    link

    题解

    没有偶环,则原图为仙人掌,一个简单环可以对应到有且仅有一个点双。
    二分图的充要条件即没有奇环,则 ([x,y]) 中不存在二分图的条件为不存在环。
    则求一遍点双之后,对于每一个询问 ([l,r]),设 (nxt_i)([i,r]) 中以 (i)(x) 时,(y) 的最大值。
    先考虑如何求 (nxt_i)。对于每一个简单环,设环内最小结点编号为 (mn),最大结点编号为 (mx),则令 (nxt_{mn} gets min { nxt_{mn}, mx })。然后从 (r)(l) 求后缀最小值,即 (nxt_i gets min { nxt_i, nxt_{i+1} })
    然后考虑如何算贡献。对于 (nxt_i leq r),以 (i)(x) 时,对 ([x,y]) 方案数的贡献为 (nxt_i - i)。对于 (nxt_i > r),以 (i)(x) 时,对 ([x,y]) 方案数的贡献为 (r - i + 1)
    显然 (nxt_i) 是单调的,那么可以二分求出最大的 (i) 满足 (nxt_i leq r)。对于第一种情况,用一个前缀和预处理。对于第二种情况,显然贡献为一个等差数列,直接算即可。
    注意二分边界!!!

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define MAX_N (300000 + 5)
    #define MAX_M (300000 + 5)
    using std::max;
    using std::min;
    int n, m, q;
    int h[MAX_N], tot;
    struct Edge {
    	int to, next;
    } e[MAX_M * 2];
    int dfn[MAX_N], low[MAX_N], cnt;
    int st[MAX_N], tp;
    int nxt[MAX_N];
    long long sum[MAX_N];
    void Read(int &x) {
    	x = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    }
    void Write(long long x) {
    	if (x >= 10) Write(x / 10);
    	putchar(x % 10 + '0');
    }
    void AddEdge(int u, int v) {
    	e[++tot].to = v;
    	e[tot].next = h[u];
    	h[u] = tot;
    }
    void Tarjan(int u) {
    	dfn[u] = low[u] = ++cnt;
    	st[++tp] = u;
    	int v;
    	for (int i = h[u]; i; i = e[i].next) {
    		v = e[i].to;
    		if (!dfn[v]) {
    			Tarjan(v);
    			low[u] = min(low[u], low[v]);
    			if (dfn[u] <= low[v]) {
    				int mn = u, mx = u, tmp = 1;
    				while (st[tp] != u) {
    					++tmp;
    					mn = min(mn, st[tp]);
    					mx = max(mx, st[tp]);
    					--tp;
    				}
    				if (tmp >= 3) nxt[mn] = min(nxt[mn], mx);
    			}
    		}
    		else low[u] = min(low[u], dfn[v]);
    	}
    }
    int main() {
    	Read(n), Read(m);
    	int u, v;
    	for (int i = 1; i <= m; ++i) Read(u), Read(v), AddEdge(u, v), AddEdge(v, u);
    	for (int i = 1; i <= n; ++i) nxt[i] = n + 1;
    	for (int i = 1; i <= n; ++i) if (!dfn[i]) Tarjan(i);
    	for (int i = n - 1; i; --i)	nxt[i] = min(nxt[i + 1], nxt[i]);
    	for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + nxt[i] - i;
    	Read(q);
    	int ql, qr, l, r, mid;
    	long long ans;
    	while (q--) {
    		Read(ql), Read(qr);
    		l = ql - 1, r = qr;
    		while (l < r) {
    			mid = l + r + 1 >> 1;
    			if (nxt[mid] > qr) r = mid - 1;
    			else l = mid;
    		}
    		ans = sum[r] - sum[ql - 1] + (long long)(qr - r + 1) * (qr - r) / 2;
    		Write(ans), putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    了解windows下的npm
    “jupyter notebook 不能导入python库但是终端上可以实现”的问题的解决
    本地创建的jupyter notebook 无法连接本地环境(即不能运行代码)
    win10 + ubuntu 下右键新建md文件(转载)
    LeetCode刷题2
    【入门】离散化
    【10.5NOIP普及模拟】sum
    【10.5NOIP普及模拟】sort
    【2020.02.01NOIP普及模拟4】怪兽
    [图论]最小花费
  • 原文地址:https://www.cnblogs.com/kcn999/p/14264435.html
Copyright © 2011-2022 走看看