Codeforces 901C. Bipartite Segments(思维题)

Posted Sakits

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 901C. Bipartite Segments(思维题)相关的知识,希望对你有一定的参考价值。

  擦。。没看见简单环。。已经想的七七八八了,就差一步

  显然我们只要知道一个点最远可以向后扩展到第几个点是二分图,我们就可以很容易地回答每一个询问了,但是怎么求出这个呢。

  没有偶数简单环,相当于只有奇数简单环,没有环套环。因为如果有环套环,必定是两个奇数环合并1个或几个点,也就是同时保持奇数或者同时变为偶数,而我们知道奇数+奇数=偶数,偶数+偶数=偶数,所以就证明了只有奇数简单环,不存在环套环。

  我们现在有一些点,再加入一个点,最多会形成一个环,并且一定是奇环,这时候,编号为1~环上的最小编号的点,最远能扩展到的编号不会超过环上最大编号。所以我们tarjan缩点求出所有环后,把每一个环按照环上最大编号排序,然后从小到大统计每一个点最远能扩展到的点就好了。

技术分享图片
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=500010, inf=1e9;
struct poi{int too, pre;}e[maxn<<1];
struct tjm{int mx, mn;}q[maxn];
int n, m, x, y, tot, tott, top, color, L, R, Q;
int last[maxn], dfn[maxn], low[maxn], st[maxn], lack[maxn], mx[maxn], mn[maxn], col[maxn], nxt[maxn];
ll sum[maxn], nxtsum[maxn];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<0 || c>9) c==- && (f=-1), c=getchar();
    while(c<=9 && c>=0) k=k*10+c-0, c=getchar();
    k*=f;
}
inline void add(int x, int y){e[++tot]=(poi){y, last[x]}; last[x]=tot;}
void tarjan(int x, int fa)
{
    dfn[x]=low[x]=++tott; st[++top]=x; lack[x]=top;
    for(int i=last[x], too;i;i=e[i].pre)
    if((too=e[i].too)!=fa)
    {
        if(!dfn[too=e[i].too]) tarjan(too, x), low[x]=min(low[x], low[too]);
        else if(!col[too]) low[x]=min(low[x], dfn[too]);    
    }
    if(dfn[x]==low[x]) 
    for(q[++color].mn=inf;lack[x]<=top;top--) 
    {
        col[st[top]]=color;
        q[color].mx=max(q[color].mx, st[top]);
        q[color].mn=min(q[color].mn, st[top]);
    }
}
inline bool cmp(tjm a, tjm b){return a.mx<b.mx;}
int main()
{
    read(n); read(m);
    for(int i=1;i<=m;i++) read(x), read(y), add(x, y), add(y, x);
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i, 0);
    sort(q+1, q+1+color, cmp);
    int j=1;
    for(int i=1;i<=color;i++)
    if(q[i].mn!=q[i].mx)
    for(;j<=q[i].mn;j++) nxt[j]=q[i].mx-1;
    for(int i=j;i<=n;i++) nxt[i]=n;
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+nxt[i]-i+1;
    read(Q);
    for(int i=1;i<=Q;i++)
    {
        read(L); read(R);
        int l=L-1, r=R;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(nxt[mid]<=R) l=mid;
            else r=mid-1;
        }
        printf("%lld\n", sum[l]-sum[L-1]+1ll*(R+1)*(R-l)-(1ll*(l+1+R)*(R-l)>>1));
    }
}
View Code

以上是关于Codeforces 901C. Bipartite Segments(思维题)的主要内容,如果未能解决你的问题,请参考以下文章

Bipartite Segments CodeForces - 901C (区间二分图计数)

Codeforces Round #640 (Div. 4)

Codeforces Round #640 (Div. 4)

2020年天大考研901数据结构与程序设计考试大纲

wt901怎么用stm32读取数据

The Best 500-901 Exam Cram Ever - Pass Easily 500 901 Exam