Description

           琥珀色黄昏像糖在很美的远方,思念跟影子在傍晚一起被拉长……
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,不存在重边、自环,不存在一条边同时存在于两个不同的简单环。
 
做法(摘自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\n",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 }
View Code