cdq分治
首先把所有没有影响的边都建出来
分治过程:
1、把左边没有右边有的边建出来
2、分治左边
3、把并查集恢复至初始的样子
4、把右边没有左边有的边建出来
5、分治右边
每次建的边数为这个区间内的集合中的边数,是一个与n无关的量,所以复杂度是正确的
O(qclogqc)
如何将并查集恢复至初始的样子?
每当一个点的父亲被修改时,将它和它的父亲入栈,每次只需要记录一下当前过程对应在栈的哪个位置即可
首先把所有没有影响的边都建出来
分治过程:
1、把左边没有右边有的边建出来
2、分治左边
3、把并查集恢复至初始的样子
4、把右边没有左边有的边建出来
5、分治右边
每次建的边数为这个区间内的集合中的边数,是一个与n无关的量,所以复杂度是正确的
O(qclogqc)
如何将并查集恢复至初始的样子?
每当一个点的父亲被修改时,将它和它的父亲入栈,每次只需要记录一下当前过程对应在栈的哪个位置即可
时间戳的思路不错
为何我的常数这么大?
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#define maxn 200010
using namespace std;
struct yts
{
int x,y;
int tim;
}e[maxn];
struct yts1
{
int c[5],cnt;
}q[maxn];
int f[maxn],st1[5000010],st2[5000100];
bool ans[maxn];
int top,n,m,T,tim;
int find(int x)
{
if (f[x]==x) return x;
int y=find(f[x]);
if (y!=f[x]) st1[++top]=x,st2[top]=f[x],f[x]=y;
return y;
}
void solve(int l,int r)
{
int Top=top;
if (l==r)
{
bool flag=1;
for (int i=1;i<=q[l].cnt;i++) if (find(e[q[l].c[i]].x)!=find(e[q[l].c[i]].y)) {flag=0;break;}
ans[l]=flag;
while (top!=Top) f[st1[top]]=st2[top],top--;
return;
}
int mid=(l+r)/2;tim++;
for (int i=l;i<=mid;i++)
for (int j=1;j<=q[i].cnt;j++)
e[q[i].c[j]].tim=tim;
for (int i=mid+1;i<=r;i++)
for (int j=1;j<=q[i].cnt;j++)
{
int x=q[i].c[j];
if (e[x].tim!=tim)
{
int f1=find(e[x].x),f2=find(e[x].y);
if (f1!=f2) st1[++top]=f1,st2[top]=f[f1],f[f1]=f2;
}
}
solve(l,mid);
while (top!=Top) f[st1[top]]=st2[top],top--;
tim++;
for (int i=mid+1;i<=r;i++)
for (int j=1;j<=q[i].cnt;j++)
e[q[i].c[j]].tim=tim;
for (int i=l;i<=mid;i++)
for (int j=1;j<=q[i].cnt;j++)
{
int x=q[i].c[j];
if (e[x].tim!=tim)
{
int f1=find(e[x].x),f2=find(e[x].y);
if (f1!=f2) st1[++top]=f1,st2[top]=f[f1],f[f1]=f2;
}
}
solve(mid+1,r);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);
scanf("%d",&T);tim=1;
for (int i=1;i<=T;i++)
{
scanf("%d",&q[i].cnt);
for (int j=1;j<=q[i].cnt;j++)
{
int x;
scanf("%d",&x);
q[i].c[j]=x;
e[x].tim=tim;
}
}
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=m;i++)
if (e[i].tim!=tim)
{
int f1=find(e[i].x),f2=find(e[i].y);
if (f1!=f2) f[f1]=f2;
}
top=0;
solve(1,T);
for (int i=1;i<=T;i++) if (ans[i]) printf("Connected\n"); else printf("Disconnected\n");
return 0;
}