做法(摘自JZOJ):我们先 DFS 出图的每一个环,得到环上编号最小和最大的节点,那么合法的区间一定不 能同时跨过这两个点。于是我们搞出一个 R 数组,R[i] 表示以 i 作为左端点时右端点最右可 以到哪个位置。R 数组显然是单调递增的。 对于询问 l, r,我们二分出一个位置 i 满足 R[l . . . i − 1] ≤ r,R[i . . . r] ≥ r,直接计算即可
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define rep(i,a,b) for (int i=a;i<=b;i++) 5 #define max(a,b) (a)>(b)?(a):(b) 6 #define min(a,b) (a)<(b)?(a):(b) 7 #define N 500007 8 using namespace std; 9 int n,m,ls[N],tot,cnt,num,top,Q; 10 int dfn[N],low[N],stack[N]; 11 int can[N]; 12 long long sum[N]; 13 14 struct edge{ 15 int to,next; 16 }e[N*2]; 17 struct arr{ 18 int mx,mi; 19 }a[N]; 20 21 void Add(int x,int y){ 22 e[++tot].to=y; 23 e[tot].next=ls[x]; 24 ls[x]=tot; 25 } 26 27 void Init(){ 28 scanf("%d%d",&n,&m); 29 rep(i,1,m){ 30 int u,v; 31 scanf("%d%d",&u,&v); 32 Add(u,v); 33 Add(v,u); 34 } 35 } 36 37 void tarjan(int x,int pre){ 38 dfn[x]=low[x]=++num; 39 stack[++top]=x; 40 for (int i=ls[x];i;i=e[i].next){ 41 int v=e[i].to; 42 if (v==pre) continue; 43 if (!dfn[v]){ 44 tarjan(v,x); 45 low[x]=min(low[x],low[v]); 46 if (dfn[x]<=low[v]){ 47 cnt++; 48 a[cnt].mi=1e9; 49 int tmp=top; 50 while(top){ 51 int y=stack[top--]; 52 a[cnt].mi=min(a[cnt].mi,y); 53 a[cnt].mx=max(a[cnt].mx,y); 54 if (y==v) break; 55 } 56 a[cnt].mi=min(a[cnt].mi,stack[top]); 57 a[cnt].mx=max(a[cnt].mx,stack[top]); 58 if (tmp-top>1) can[a[cnt].mi]=min(can[a[cnt].mi],a[cnt].mx-1); 59 } 60 } 61 else low[x]=min(low[x],dfn[v]); 62 } 63 } 64 65 void Work(){ 66 scanf("%d",&Q); 67 while(Q--){ 68 int x,y; 69 long long ans=0; 70 scanf("%d%d",&x,&y); 71 int l=x,r=y,pos; 72 while (l<=r){ 73 int mid=(l+r)/2; 74 if (can[mid]>=y) pos=mid,r=mid-1; 75 else l=mid+1; 76 } 77 ans=sum[pos-1]-sum[x-1]; 78 ans+=(long long)(y-pos+1)*(y-pos+2)/2; 79 printf("%lld ",ans); 80 } 81 } 82 83 84 int main(){ 85 freopen("graph.in","r",stdin); 86 freopen("graph.out","w",stdout); 87 Init(); 88 rep(i,1,n) can[i]=n; 89 rep(i,1,n) if(!dfn[i]) tarjan(i,0); 90 for(int i=n-1;i>=1;i--) can[i]=min(can[i],can[i+1]); 91 for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(long long)(can[i]-i+1); 92 Work(); 93 }