1. 程式人生 > >JZOJ5919. 【NOIP2018模擬10.22】逛公園

JZOJ5919. 【NOIP2018模擬10.22】逛公園

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 行,每行一個整數表示答案。

Data Constraint

對於 30% 的資料,n, m ≤ 100。
對於另外 10% 的資料,n = m + 1。
對於另外 10% 的資料,n = m
對於 100% 的資料,n, m ≤ 3 × 10^5, xi ≤ yi,不存在重邊、自環,不存在一條邊同時存在於兩個不同的簡單環。

題解

根據資料範圍的最後,可以知道給出的是一棵仙人掌。
考慮一個簡單環的影響,
已知這個簡單環的編號最小值和最大值,
那麼選擇區間[l,r]的時候就一定不能跨過這個最小最大值的區間。
那麼設 f

i f_i 表示i為左端點的區間,右端點最遠可以擴充套件到哪一個位置。
很顯然,f是遞增的。
對於一組詢問[l,r]就應該在區間[l,r]裡面找到應該位置x,
使得 f x
1 < r f x r f_{x-1}<r 且 f_x≥r
那麼在x之前的全部位置對於的右端點都是 f i f_i
而從x這個位置開始往後,所以的右端點都是r。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 3000003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int nxt[N*2],to[N*2],lst[N],tot,x,y,z[N],top;
int n,m,q,l,r,mid,f[N];
bool bz[N],is[N];
ll ans,sum[N],S[N];

void ins(int x,int y)
{
	nxt[++tot]=lst[x];
	to[tot]=y;
	lst[x]=tot;
}

void dfs(int x,int fa)
{
	bz[z[++top]=x]=0;
	is[x]=1;
	for(int i=lst[x];i;i=nxt[i])
	{
		if(to[i]==fa)continue;
		if(bz[to[i]])dfs(to[i],x);else
		{
			if(!is[to[i]])continue;
			int mi=to[i],mx=to[i];
			for(int j=top;z[j]^to[i];j--)mx=max(z[j],mx),mi=min(z[j],mi);
			f[mi]=min(f[mi],mx-1);
		}
	}
	top--;is[x]=0;
}

int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	memset(f,127,sizeof(f));
	memset(bz,1,sizeof(bz));
	read(n);read(m);
	for(int i=1;i<=m;i++)
		read(x),read(y),ins(x,y),ins(y,x);
	dfs(1,0);
	for(int i=n;i;i--)f[i]=min(f[i],f[i+1]);
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+f[i]-i+1,S[i]=S[i-1]+i;
	for(read(q);q;q--)
	{
		read(x);read(y);
		for(l=x,r=y;l<r;)
		{
			mid=(l+r)>>1;
			if(f[mid]<y)l=mid+1;else r=mid;
		}
		ans=sum[l-1]-sum[x-1]+S[y-l+1];
		write(ans);P('\n');
	}
	
	return 0;
}