Codeforces 901C. Bipartite Segments(思維題)
阿新 • • 發佈:2017-12-27
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;View Codeint 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)); } }
Codeforces 901C. Bipartite Segments(思維題)