JZOJ-senior-5919. 【NOIP2018模擬10.21】逛公園
阿新 • • 發佈:2018-11-08
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
琥珀色黃昏像糖在很美的遠方,思念跟影子在傍晚一起被拉長……
小 B 帶著 GF 去逛公園,公園一共有 n 個景點,標號為 1 . . . n。景點之間有 m 條路徑相連。
小 B 想選擇編號在一段區間 [l, r] 內的景點來遊玩,但是如果這些景點的誘導子圖形成了環,那麼 GF 將會不高興。
小 B 給出很多個詢問 [x, y],想讓你求有多少個區間 [l, r] 滿足 x ≤ l, r ≤ y 且不會使 GF不高興。
Input
第一行為兩個整數 n, m,表示景點和路徑的數量。
第 2 . . . m + 1 行每行兩個整數 ui, vi 表示第 i 路徑的兩端。
第 m + 2 行是一個整數 q 表示詢問的個數,接下來 m 行每行兩個整數 xi, yi 表示詢問。
Output
q 行,每行一個整數表示答案。
Sample Input
8 9
1 2
2 3
3 1
4 5
5 6
6 7
7 8
8 4
7 2
3
1 8
1 4
3 8
Sample Output
27
8
19
Data Constraint
對於 30% 的資料,n, m ≤ 100。
對於另外 10% 的資料,n = m + 1。
對於另外 10% 的資料,n = m
對於 100% 的資料,n, m ≤ 3 × 10^5, xi ≤ yi,不存在重邊、自環,不存在一條邊同時存在於兩個不同的簡單環。
Hint
誘導子圖:子圖 G′ = (V′, E′),原圖 G = (V, E)。V′ 是 V 的子集,E′ = {(u, v)|u, v ∈V′,(u, v) ∈ E}
Solution
- 題目意思就是求出不包含環的區間的個數
- 顯然對於每個點開始往右最遠可達的位置是遞增的
- 我們在找環的時候就處理好每個點往右最遠可達的不包含環的位置,記為
- 為方便求答案,處理出字首和陣列
- 對於每個詢問 ,我們將 的字首和求,後面的等差數列求和即可
Code
#include<algorithm>
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=3e5+5;
int n,m,q,num,cnt,time;
int R[N],z[N],dfn[N],low[N],last[N];
ll S[N];
struct edge{int to,next;}e[2*N];
void link(int x,int y)
{
e[++num]=(edge){y,last[x]},last[x]=num;
}
void Tarjan(int x,int fa)
{
dfn[x]=low[x]=++time,z[++z[0]]=x;
for(int w=last[x];w;w=e[w].next)
{
int y=e[w].to;
if(y==fa) continue;
if(!dfn[y])
{
Tarjan(y,x),low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y])
{
int mn=n+1,mx=0,gs=z[0];
while(z[0])
{
int now=z[z[0]--];
mn=min(mn,now);
mx=max(mx,now);
if(now==y) break;
}
mn=min(mn,z[z[0]]);
mx=max(mx,z[z[0]]);
if(gs-z[0]>1) R[mn]=min(R[mn],mx-1);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y),link(y,x);
}
fo(i,1,n) R[i]=n;
fo(i,1,n) if(!dfn[i]) Tarjan(1,0);
fd(i,n-1,1) R[i]=min(R[i],R[i+1]);
fo(i,1,n) S[i]=S[i-1]+R[i]-i+1;
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int pos=upper_bound(R+x,R+y,y)-R;
ll ans=(ll)S[pos-1]-S[x-1]+(ll)(1+y-pos+1)*(ll)(y-pos+1)/2;
printf("%lld\n",ans);
}
}