题意简述
n
个点
数据范围
1≤n,m,q≤2×105
思路
把所有询问离线后排序,按照右端点的边的序号递增的顺序处理。
边的序号即为它的权值,把边也看成点加入LCT,维护最大生成森林。
每次加入一个边(点),找到它形成的环上权值最小的一个点,删除之。
用树状数组维护在最大生成森林中的边。
每次查询用树状数组查询[L,R]区间。
复杂度
O((n+m+q)logn)
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200010
#define INF 0x3f3f3f3f
struct Qe{
int l,r,id;
bool operator < (const Qe &n1) const
{
return r<n1.r;
}
}Q[MAXN];
int T,n,m,q;
int x[MAXN],y[MAXN],ans[MAXN];
bool is_in[MAXN];
namespace LCT
{
struct Node{
Node *fa,*ch[2];
bool rev;
int data,mn,pos,id;
bool chlr()
{
return fa->ch[1]==this;
}
bool is_rt()
{
return fa->ch[0]!=this&&fa->ch[1]!=this;
}
void modify_rev()
{
rev^=1;
swap(ch[0],ch[1]);
}
void pushup()
{
mn=min(min(ch[0]->mn,ch[1]->mn),data);
if (data<ch[0]->mn&&data<ch[1]->mn)
pos=id;
else if (ch[0]->mn<ch[1]->mn)
pos=ch[0]->pos;
else
pos=ch[1]->pos;
}
void pushdown()
{
if (rev)
{
ch[0]->modify_rev();
ch[1]->modify_rev();
rev=0;
}
}
Node();
void Clear();
}*null=new Node;
Node::Node()
{
fa=ch[0]=ch[1]=null;
rev=0;
data=mn=INF;
pos=-1;
}
void Node::Clear()
{
fa=ch[0]=ch[1]=null;
rev=0;
data=mn=INF;
pos=-1;
}
void init()
{
*null=Node();
}
void rotate(Node *k)
{
Node *r=k->fa;
int x=k->chlr();
r->ch[x]=k->ch[x^1];
k->ch[x^1]->fa=r;
if (!r->is_rt())
r->fa->ch[r->chlr()]=k;
k->fa=r->fa;
k->ch[x^1]=r;
r->fa=k;
r->pushup();
}
void fix(Node *k)
{
if (!k->is_rt())
fix(k->fa);
k->pushdown();
}
void splay(Node *k)
{
fix(k);
for (;!k->is_rt();rotate(k))
if (!k->fa->is_rt())
rotate(k->fa->chlr()==k->chlr() ? k->fa : k);
k->pushup();
}
Node *access(Node *k)
{
Node *r=null;
for (;k!=null;r=k,k=k->fa)
{
splay(k);
k->ch[1]=r;
}
return r;
}
void mk_rt(Node *k)
{
access(k)->modify_rev();
splay(k);
}
Node *find_rt(Node *k)
{
splay(k);
Node *ret=k;
while (ret->ch[0]!=null)
{
ret=ret->ch[0];
ret->pushdown();
}
return ret;
}
void link(Node *k,Node *r)
{
mk_rt(r);
r->fa=k;
}
void cut(Node *k,Node *r)
{
mk_rt(r);
access(k);
splay(k);
k->ch[0]=null;
r->fa=null;
k->pushup();
}
int query(Node *k,Node *r)
{
mk_rt(r);
access(k);
if (find_rt(k)!=find_rt(r))
return -1;
splay(k);
return k->mn==INF ? -1 : k->pos;
}
}
struct BIT{
static const int size=200000;
int d[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void modify(int x,int val)
{
for (;x<=size;x+=lowbit(x))
d[x]+=val;
}
int query(int l,int r)
{
int ret=0;
for (;r;r-=lowbit(r))
ret+=d[r];
for (l--;l;l-=lowbit(l))
ret-=d[l];
return ret;
}
}BI;
LCT::Node G[MAXN<<1];
int main()
{
LCT::init();
for (int i=1;i<=400000;i++)
G[i].id=i;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=m;i++)
scanf("%d%d",&x[i],&y[i]);
for (int i=1;i<=n;i++)
{
G[i].data=INF;
G[i].pushup();
}
for (int i=1;i<=m;i++)
{
G[n+i].data=i;
G[i].pushup();
}
for (int i=1;i<=q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+1,Q+q+1);
int now=1;
for (int i=1;i<=m;i++)
{
if (x[i]!=y[i])
{
int tmp=LCT::query(&G[x[i]],&G[y[i]]);
if (tmp!=-1)
{
LCT::cut(&G[x[tmp-n]],&G[tmp]);
LCT::cut(&G[y[tmp-n]],&G[tmp]);
BI.modify(tmp-n,-1);
is_in[tmp-n]=0;
}
LCT::link(&G[x[i]],&G[n+i]);
LCT::link(&G[y[i]],&G[n+i]);
BI.modify(i,1);
is_in[i]=1;
}
while (now<=q&&Q[now].r==i)
{
ans[Q[now].id]=n-BI.query(Q[now].l,Q[now].r);
now++;
}
}
for (int i=1;i<=n+m;i++)
G[i].Clear();
for (int i=1;i<=m;i++)
if (is_in[i])
{
BI.modify(i,-1);
is_in[i]=0;
}
for (int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
return 0;
}