n<=300000,m<=300000的图,图上只有奇环,q<=300000个询问每次问:一个区间内有多少个子区间,满足只保留编号在该区间的点以及他们之间的边,可以构成一个二分图。
终于走出了第一步。。Pi--从点i开始往前延伸最早到哪里就不是二分图了。由于这个数组是单调的,只要这个数组求出来就可以回答询问:每次回答询问时,输出$sum_{i=L}^{R} Max(L-1,P_i)$即可。
然后就是这个数组怎么求了。。要支持删除点、插入点、查询是不是二分图。。LCT??并查集??动态图??懵逼。。。
然而题目有特殊性质。。只有奇环就是没有环套环的意思啦,如果有环套环肯定是有偶环的,然后在一个环内,最大编号a,最小编号b,那么相当于对$[a,n]$区间的P数组对b取个Max。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 //#include<queue> 6 //#include<math.h> 7 //#include<time.h> 8 //#include<iostream> 9 using namespace std; 10 11 int n,m,q; 12 #define maxn 300011 13 #define maxm 600011 14 struct Edge{int to,next;}; 15 struct Graph 16 { 17 Edge edge[maxm]; int first[maxn],le; 18 Graph() {le=2; memset(first,0,sizeof(first));} 19 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 20 void insert(int x,int y) {in(x,y); in(y,x);} 21 }g,bg; 22 23 #define LL long long 24 int p[maxn]; LL sum[maxn]; 25 26 int dfn[maxn],low[maxn],Time=0,sta[maxn],top=0,tag[maxn]; bool insta[maxn]; 27 void tarjan(int x,int fa) 28 { 29 // cout<<"tarjan"<<x<<endl; 30 dfn[x]=low[x]=++Time; 31 sta[++top]=x; insta[x]=1; 32 for (int i=g.first[x];i;i=g.edge[i].next) 33 { 34 const Edge &e=g.edge[i]; if (e.to==fa) continue; 35 if (!dfn[e.to]) tarjan(e.to,x),low[x]=min(low[x],low[e.to]); 36 else if (insta[e.to]) low[x]=min(low[x],dfn[e.to]); 37 } 38 if (dfn[x]==low[x]) 39 { 40 int Min=0x3f3f3f3f,Max=0; 41 while (sta[top]!=x) Min=min(Min,sta[top]),Max=max(Max,sta[top]),insta[sta[top]]=0,top--; 42 Min=min(Min,x); Max=max(Max,x); top--; insta[x]=0; 43 if (Min!=Max) tag[Max]=max(tag[Max],Min); 44 } 45 } 46 47 int main() 48 { 49 scanf("%d%d",&n,&m); 50 for (int i=1,x,y;i<=m;i++) 51 { 52 scanf("%d%d",&x,&y); 53 g.insert(x,y); 54 } 55 56 for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0); 57 int now=0; 58 for (int i=1;i<=n;i++) now=max(now,tag[i]),p[i]=now; 59 // for (int i=1;i<=n;i++) cout<<p[i]<<' ';cout<<endl; 60 61 for (int i=1;i<=n;i++) sum[i]=sum[i-1]+p[i]; 62 scanf("%d",&q); 63 while (q--) 64 { 65 int x,y; scanf("%d%d",&x,&y); 66 int L=x,R=y+1; 67 while (L<R) 68 { 69 const int mid=(L+R)>>1; 70 if (p[mid]>=x) R=mid; 71 else L=mid+1; 72 } 73 printf("%lld ",-1ll*(x-1)*(L-x)-(sum[y]-sum[L-1])+1ll*(x+y)*(y-x+1)/2); 74 } 75 return 0; 76 }