1. 程式人生 > >Codeforces 901C. Bipartite Segments(思維題)

Codeforces 901C. Bipartite Segments(思維題)

lose struct ostream part pan -i lap read har

  擦。。沒看見簡單環。。已經想的七七八八了,就差一步

  顯然我們只要知道一個點最遠可以向後擴展到第幾個點是二分圖,我們就可以很容易地回答每一個詢問了,但是怎麽求出這個呢。

  沒有偶數簡單環,相當於只有奇數簡單環,沒有環套環。因為如果有環套環,必定是兩個奇數環合並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(思維題)