题目链接
给出一张图,每次询问删去图中一些边后(边数不超过4)图的连通性
首先删边是不好处理的,于是我们要把没有删掉的边加入
考虑到被删掉边只有4条,那么每一次加边其实有很多是加重了的,可以看出是线段树分治了
每一条边影响的询问被分为很多段
通过标记永久化和树上dfs栈序撤销操作来批量处理与询问有关的修改
加边等价于修改操作
P.S:跑得很慢.....
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
const int N=2e5+10;
int n,m,K;
#define ls (now<<1)
#define rs (now<<1|1)
namespace segment_tree{
struct edge{int u,v;}a[N];
struct set{int fa;int size;int dep;}F[N];
vector<int> V[21*N];
int fir[N];//每一条边当前应该添加的起始位置,断点就是删掉它的询问
inline int find(int x){return (F[x].fa==x)? x:find(F[x].fa);}
void insert(int now,int l,int r,int L,int R,int x){
if(l>=L&&r<=R){V[now].push_back(x);return;}
register int mid=l+r>>1;
if(mid>=L) insert(ls,l,mid,L,R,x);
if(mid1,r,L,R,x);
return;
}
void init()
{
register int u,v;
for(register int i=1;i<=n;++i) F[i]=(set){i,1,1};
for(register int i=1;i<=m;++i){u=read();v=read();a[i]=(edge){u,v};fir[i]=1;}
K=read();
for(register int i=1;i<=K;++i)
{
register int num=read();
for(register int j=1;j<=num;++j){
u=read();
if(fir[u]<=i-1) insert(1,1,K,fir[u],i-1,u);
fir[u]=i+1;
}
}
for(register int i=1;i<=m;++i) if(fir[i]<=K) insert(1,1,K,fir[i],K,i);
return;
}
stack< set > S;int top=0;
void segment_Div(int now,int l,int r){
register int tp1=top;
register int mid=l+r>>1;
for(register int i=0;iregister int e=V[now][i];
register int fx=find(a[e].u),fy=find(a[e].v);
if(fx==fy) continue;
if(F[fx].dep>F[fy].dep) swap(fx,fy);
top+=2;
S.push(F[fx]);S.push(F[fy]);
F[fx].fa=fy;F[fy].dep=max(F[fy].dep,F[fx].dep+1);F[fy].size+=F[fx].size;
}
if(l==r) {register int fx=find(1);if(F[fx].size==n) puts("Connected");else puts("Disconnected");}
else segment_Div(ls,l,mid),segment_Div(rs,mid+1,r);
while(top!=tp1) {--top;register set T=S.top();S.pop();F[T.fa]=T;}
return;
}
}
int main()
{
n=read();m=read();
segment_tree::init();
segment_tree::segment_Div(1,1,K);
return 0;
}