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

    Description

    给一个 (n) 个点 (m) 条边的、不含偶环的无向图,每次询问 ([l,r]) ,求 ([l,r]) 中有多少 ([x,y]) 使得编号在 ([x,y]) 中的点组成的诱导子图是一个二分图。

    (n,m,qle 3 imes 10^5)

    Solution

    显然这个图是一个奇环仙人掌。于是在这张图中,是二分图的充要条件是不含环。

    于是预处理边双连通分量,记录每个 (ebc) 的编号最小和最大点,记为 (mn[i])(mx[i])

    那么就可以记录一个数组 (s[i]) ,表示编号为 (i) 的点向右最远可以可以扩展到 (s[i]) ,使得 ([i,s[i]]​) 的点组成的诱导子图是二分图。

    所以初始 (s[mn[i]]=mx[i] - 1) ,再用一个后缀最小值就可以得到 (s) 数组。显然 (s) 单调不减。

    考虑如何回答询问。考虑一个中转点 (p) ,满足 (forall i in [l,p-1],s[i]<r) 以及 (forall iin[p,r],s[i]>=r) ,那么答案等于

    [(sum_{i=l}^{p-1}s[i]-i+1)+(sum_{i=p}^rr-i+1) ]

    #include<bits/stdc++.h>
    using namespace std;
    
    template <class T> void read(T &x) {
    	x = 0; bool flag = 0; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) flag |= ch == '-';
    	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48; flag ? x = ~x + 1 : 0;
    }
    
    #define N 300010
    #define rep(i, a, b) for (auto i = (a); i <= (b); i++)
    #define drp(i, a, b) for (auto i = (a); i >= (b); i--)
    #define ll long long
    
    struct { int v, next; }e[N << 1];
    int head[N];
    bool isBridge[N << 1];
    inline void add(int u, int v) {
    	static int tot = 1; e[++tot].v = v, e[tot].next = head[u], head[u] = tot;
    }
    
    int dfn[N], low[N];
    void tarjan(int u, int fa) {
    	static int ind; dfn[u] = low[u] = ++ind;
    	for (int i = head[u], v; i; i = e[i].next) {
    		if (!dfn[v = e[i].v]) {
    			tarjan(v, u), low[u] = min(low[u], low[v]);
    			if (low[v] > dfn[u]) isBridge[i] = isBridge[i ^ 1] = 1;
    		}
    		else if (dfn[v] < dfn[u] && v ^ fa) low[u] = min(low[u], dfn[v]);
    	}
    }
    
    int bl[N], siz[N];
    void dfs(int u, int ebc) {
    	siz[bl[u] = ebc]++;
    //	printf("%d
    ", u);
    	for (int i = head[u]; i; i = e[i].next) if (!bl[e[i].v] && !isBridge[i]) dfs(e[i].v, ebc);
    }
    
    int mn[N], mx[N], s[N];
    ll sum[N];
    
    int main() {
    	int n, m; read(n), read(m);
    	rep(i, 1, m) {
    		int u, v; read(u), read(v);
    		add(u, v), add(v, u);
    	}
    	rep(i, 1, n) if (!dfn[i]) tarjan(i, 0);
    	int ebc = 0;
    	rep(i, 1, n) if (!bl[i]) dfs(i, ++ebc);
    	rep(i, 1, n) mx[bl[i]] = i;
    	drp(i, n, 1) mn[bl[i]] = i;
    	rep(i, 1, n) s[i] = n;
    	rep(i, 1, ebc) if (siz[i] > 1) s[mn[i]] = mx[i] - 1;
    	drp(i, n - 1, 1) s[i] = min(s[i], s[i + 1]);
    	rep(i, 1, n) sum[i] = sum[i - 1] + s[i] - i + 1;
    	int q; read(q);
    	while (q--) {
    		int l, r; read(l), read(r);
    		int p = lower_bound(s + l, s + r + 1, r) - s;
    		printf("%lld
    ", 1ll * (r - p + 1) * (r - p + 2) / 2 + sum[p - 1] - sum[l - 1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现蓝桥杯VIP算法训练 纪念品分组
    Java实现蓝桥杯VIP算法训练 纪念品分组
    linux下syscall函数,SYS_gettid,SYS_tgkill
    可变参数宏__VA_ARGS__和...
  • 原文地址:https://www.cnblogs.com/aziint/p/9643134.html
Copyright © 2011-2022 走看看