正题
题目链接:https://gmoj.net/senior/#main/show/4739
题目大意
nnn个点mmm条边的一张图,qqq次询问一个区间的边可以形成多少连通块。
解题思路
询问按照右端点排序,然后边权就是编号,这样询问最大生成树后判断有多少个边权大于lll即可。用LCTLCTLCT维护这个最大生成树然后用树状数组记录每条边的权值。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
当然也可以莫队做,维护到每个块时的情况,然后右指针右移,左指针右移是暴力还原到每个块的末尾即可。
时间复杂度O(nn)O(n\sqrt n)O(nn)
当然这里是用LCTLCTLCT做的。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define lowbit(x) (x&-x)
using namespace std;
const int N=4e5+10;
struct node{int x,y,id;
}a[N],p[N];
int n,m,q,val[N],sum[N],ans[N],fa[N];
struct Link_Cut_Tree{int t[N][2],fa[N];bool r[N];stack<int>s;bool Nroot(int x){return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}bool Direct(int x){return t[fa[x]][1]==x;}void PushUp(int x){sum[x]=min(val[x],min(sum[t[x][0]],sum[t[x][1]]));return;}void Rev(int x){swap(t[x][0],t[x][1]);r[x]^=1;return;}void PushDown(int x){if(!r[x])return;Rev(t[x][0]);Rev(t[x][1]);r[x]^=1;return;}void Rotate(int x){int y=fa[x],z=fa[fa[x]];int xs=Direct(x),ys=Direct(y);int w=t[x][!xs];t[y][xs]=0;t[y][xs]=w;t[x][!xs]=y;if(Nroot(y))t[z][ys]=x;if(w)fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);PushUp(x);return;}void Splay(int x){s.push(x);while(Nroot(s.top())) s.push(fa[s.top()]);while(!s.empty()) PushDown(s.top()),s.pop();while(Nroot(x)){int y=fa[x];if(!Nroot(y))Rotate(x);else if(Direct(x)==Direct(y))Rotate(y),Rotate(x);else Rotate(x),Rotate(x); }return;}void Access(int x){for(int y=0;x;x=fa[y=x])Splay(x),t[x][1]=y,PushUp(x);return;}void MakeRoot(int x){Access(x);Splay(x);Rev(x);return;}int Split(int x,int y){MakeRoot(x);Access(y);Splay(y);return sum[y];}void Link(int x,int y){MakeRoot(x);fa[x]=y;Access(x);return;}void Cut(int x,int y){MakeRoot(y);Access(x);Splay(x);fa[t[x][0]]=0;t[x][0]=0;PushUp(x);return;}
}LCT;
struct Tree_Array{int t[N];void Change(int x,int val){while(x<=m){t[x]+=val;x+=lowbit(x);}return;}int Ask(int x){int ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;}
}T;
int find(int x)
{return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
bool cmp(node x,node y)
{return x.y<y.y;}
int main()
{scanf("%d%d%d",&n,&m,&q);memset(val,0x3f,sizeof(val));memset(sum,0x3f,sizeof(sum));for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d",&a[i].x,&a[i].y);val[i+n]=sum[i+n]=i;}for(int i=1;i<=q;i++)scanf("%d%d",&p[i].x,&p[i].y),p[i].id=i;sort(p+1,p+1+q,cmp);int z=0;for(int i=1;i<=q;i++){while(z<m&&z<p[i].y){z++;int x=a[z].x,y=a[z].y;if(x==y)continue;int X=find(x),Y=find(y);if(X==Y){int w=LCT.Split(x,y);LCT.Cut(w+n,a[w].x);LCT.Cut(w+n,a[w].y);T.Change(w,-1);}else fa[X]=Y;LCT.Link(x,z+n);LCT.Link(y,z+n);T.Change(z,1);}ans[p[i].id]=n-(T.Ask(p[i].y)-T.Ask(p[i].x-1));}for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
}