n条线段 [ l , r ] [l,r] [l,r],有m组询问 [ x , y ] [x,y] [x,y],求有多少个 [ x , y ] [x,y] [x,y]的子区间(含 [ x , y ] [x,y] [x,y])不覆盖任意一条线段。
顺便复习了下tarjan求点双。
审题!
去重貌似是很麻烦的。
用比较简单的方法。
突破口:固定住左端点,扩右端点,直到不能扩为止。通过这样来计算。
设 m x [ i ] mx[i] mx[i]表示以i为左端点,右端点最多能到哪。
显然, m x [ i ] mx[i] mx[i]是递增的。
所以,在 [ x , y ] [x,y] [x,y]中二分出一个点z, i ∈ [ z , y ] i∈[z,y] i∈[z,y],mx[i]>y
区间 [ z , y ] [z,y] [z,y]的所有子区间都是合法的。而 i ∈ [ x , z ) i∈[x,z) i∈[x,z),对答案的贡献为 m x [ i ] − i + 1 mx[i]-i+1 mx[i]−i+1,用树状数组维护个前缀和就好了。
①第一突破口,固定住左端点,扩右端点,直到不能扩为止。
②第二突破口, m x [ i ] mx[i] mx[i]是递增的。
③位置i对答案的贡献为关于i的函数 c o n t r i b u t e ( i ) contribute(i) contribute(i)
#include
#include
#include
#include
#include
#define N 600010
#define LL long long
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct Graph{
int tot,head[N],next[N<<1],to[N<<1];
void lb(int x,int y){to[++tot]=y;next[tot]=head[x];head[x]=tot;}
}G;
int i,j,k,l1,r1,n,m,q,cs;
int Mx,Mn,u,v,w,wz,mid;
int r[N];
int opl,opr,opx,opz,TOT;
int dfn[N],low[N],st[N],T,top;
bool Bz[N];
LL tr[N];
LL ans;
int read(){
int fh=0,rs=0;char ch=0;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh?-rs:rs;
}
void write(int x){
if(x>9)write(x/10);
P(x%10+'0');
}
int Min(int x,int y){return x<y?x:y;}
int Max(int x,int y){return x>y?x:y;}
void tarjan(int x){
int i,c0;
Bz[x]=1;
st[++top]=x;
dfn[x]=low[x]=++T;
for(i=G.head[x];i;i=G.next[i])
if(!dfn[G.to[i]]){
tarjan(G.to[i]);
low[x]=Min(low[x],low[G.to[i]]);
if(low[G.to[i]]>=dfn[x]){
Mn=Mx=x;
c0=0;
while(st[top+1]^G.to[i]){
c0++;
Mn=Min(Mn,st[top]);
Mx=Max(Mx,st[top]);
top--;
}
if(c0>1){
r[Mn]=Min(r[Mn],Mx-1);
}
}
}else low[x]=Min(low[x],dfn[G.to[i]]);
}
int lowbit(int x){return x&(-x);}
void add(int x,LL z){
for(;x<=n;x=x+lowbit(x))tr[x]=tr[x]+z;
}
LL qry(int x){
LL rs=0;
for(;x;x=x-lowbit(x))rs=rs+tr[x];
return rs;
}
LL calc(LL x){return x*(x+1)>>1;}
int main(){
n=read();m=read();
fo(i,1,n)r[i]=n;
r[n+1]=n+1;
fo(i,1,m){
u=read(),v=read();
G.lb(u,v);
G.lb(v,u);
}
fo(i,1,n)if(!Bz[i]){
tarjan(i);
}
fd(i,n-1,1)r[i]=Min(r[i+1],r[i]);
fo(i,1,n)add(i,r[i]-i+1);
q=read();
fo(cs,1,q){
u=read(),v=read();
l1=u,r1=v+1;w=r1;
while(l1<=r1){
mid=(l1+r1)>>1;
if(r[mid]>v)w=mid,r1=mid-1;else l1=mid+1;
}
ans=qry(w-1)-qry(u-1)+calc(v-w+1);
printf("%lld\n",ans);
}
return 0;
}