JZOJ 5919. 【NOIP2018模擬10.22】逛公園
阿新 • • 發佈:2018-11-01
題目
n條線段 ,有m組詢問 ,求有多少個 的子區間(含 )不覆蓋任意一條線段。
題解
順便複習了下tarjan求點雙。
審題!
去重貌似是很麻煩的。
用比較簡單的方法。
突破口:固定住左端點,擴右端點,直到不能擴為止。通過這樣來計算。
設
表示以i為左端點,右端點最多能到哪。
顯然,
是遞增的。
所以,在
中二分出一個點z,
,mx[i]>y
區間
的所有子區間都是合法的。而
,對答案的貢獻為
,用樹狀陣列維護個字首和就好了。
小結
①第一突破口,固定住左端點,擴右端點,直到不能擴為止。
②第二突破口,
是遞增的。
③位置i對答案的貢獻為關於i的函式
程式碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#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;
}