Description

pps

Input

pps

Output

pps

Sample Input

4 5
1 2
2 3
3 4
4 1
2 4
3
1 5
2 2 3
2 1 2

Sample Output

Connected
Disconnected
Connected

HINT

N<=100000 M<=200000 K<=100000

Source

思路

cdq分治,用并查集维护图,首先将任何询问都没有涉及到的边都添加到并查集中;
对于分治的一个区间的询问:
1. 首先将右区间有左区间没有的边添加到并查集中;
2. 递归处理左区间;
3. 还原并查集到递归这个区间的初始状态;
4. 将左区间有右区间没有的边添加到并查集中;
5. 递归处理右区间;
6. 同3
并查集可以用按秩合并。

代码

#include <cstdio>

const int maxn=100000;
const int maxm=1000000;

template<typename t>
struct stack
{
  t s[maxn+10];
  int head;

  inline int push(t x)
  {
    s[++head]=x;
    return 0;
  }

  inline int pop()
  {
    --head;
    return 0;   
  }

  inline t top()
  {
    return s[head];
  }

  inline int size()
  {
    return head;
  }
};

struct data
{
  int num,pr,t;
};

inline data make_data(int num_,int pr_,int t_)
{
  data res;
  res.num=num_;
  res.pr=pr_;
  res.t=t_;
  return res;
}

int n,tt;

struct union_find_set
{
  int fa[maxn+10],h[maxn+10],cnt;
  stack<data> st;

  inline int find(int x)
  {
    return fa[x]?find(fa[x]):x;
  }

  inline int merge(int x,int y,int kind,int ti)
  {
    x=find(x);
    y=find(y);
    if(x==y)
      {
        return 1;
      }
    --cnt;
    if(h[x]>h[y])
      {
        fa[y]=x;
        if(kind)
          {
            st.push(make_data(y,h[x],ti));
          }
      }
    else
      {
        fa[x]=y;
        if(kind)
          {
            st.push(make_data(x,h[y],ti));
          }
        if(h[x]==h[y])
          {
            ++h[y];
          }
      }
    return 0;
  }

  inline int split(int ti)
  {
    while(st.size())
      {
        data d=st.top();
        if(d.t!=ti)
          {
            return 0;
          }
        st.pop();
        h[fa[d.num]]=d.pr;
        fa[d.num]=0;
        ++cnt;
      }
    return 0;
  }
};

union_find_set s;
int m,k,c[maxm+10],q[maxm+10][4],line[maxm+10][2],ans[maxm+10];
int tmp[maxm+10];

int solve(int l,int r)
{
  if(l==r)
    {
      if(s.cnt==1)
        {
          ans[l]=0;
        }
      else
        {
          ans[l]=1;
        }
      return 0;
    }
  ++tt;
  int mid=(l+r)>>1;
  for(register int i=mid+1; i<=r; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=1;
        }
    }
  for(register int i=l; i<=mid; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=0;
        }
    }
  for(register int i=mid+1; i<=r; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          if(tmp[q[i][j]]==1)
            {
              s.merge(line[q[i][j]][0],line[q[i][j]][1],1,tt);
            }
        }
    }
  solve(l,mid);
  s.split(tt);
  for(register int i=l; i<=mid; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=1;
        }
    }
  for(register int i=mid+1; i<=r; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=0;
        }
    }
  for(register int i=l; i<=mid; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          if(tmp[q[i][j]]==1)
            {
              s.merge(line[q[i][j]][0],line[q[i][j]][1],1,tt);
            }
        }
    }
  solve(mid+1,r);
  s.split(tt);
  for(register int i=l; i<=mid; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=0;
        }
    }
  --tt;
  return 0;
}

int main()
{
  scanf("%d%d",&n,&m);
  for(register int i=1; i<=m; ++i)
    {
      scanf("%d%d",&line[i][0],&line[i][1]);
    }
  scanf("%d",&k);
  for(register int i=1; i<=k; ++i)
    {
      scanf("%d",&c[i]);
      for(register int j=0; j<c[i]; ++j)
        {
          scanf("%d",&q[i][j]);
        }
    }
  s.cnt=n;
  for(register int i=1; i<=n; ++i)
    {
      s.h[i]=1;
    }
  for(register int i=1; i<=k; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=1;
        }
    }
  for(register int i=1; i<=m; ++i)
    {
      if(!tmp[i])
        {
          s.merge(line[i][0],line[i][1],0,0);
        }
    }
  for(register int i=1; i<=k; ++i)
    {
      for(register int j=0; j<c[i]; ++j)
        {
          tmp[q[i][j]]=0;
        }
    }
  solve(1,k);
  for(register int i=1; i<=k; ++i)
    {
      if(ans[i])
        {
          puts("Disconnected");
        }
      else
        {
          puts("Connected");
        }
    }
  return 0;
}