[边双连通分量 缩点 虚树 欧拉序列LCA] Codeforces 639F VK Cup 2016 - Round 1 F. Bear and Chemistry

7 篇文章 0 订阅
3 篇文章 0 订阅

这道题就是缩缩缩!

先把原图缩成一个双连通树 然后查询的时候把所有关键点缩成一颗虚树 加完询问里的边 在缩一次双连通

这里缩虚树的时候LCA用欧拉序列做 怕倍增太慢


#include<cstdio>  
#include<cstdlib>  
#include<algorithm>  
#include<cstring>  
#include<cmath>
#include<stack>
#define cl(x) memset(x,0,sizeof(x))  
using namespace std;  
  
inline char nc(){  
  static char buf[100000],*p1=buf,*p2=buf;  
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }  
  return *p1++;  
}  
  
inline void read(int &x){  
  char c=nc(),b=1;  
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;  
}  

const int N=300005;

struct edge{
  int u,v,next;
}G[N*20];
int head1[N],head2[N],head3[N],inum=1;
int *head;
int tag[N<<1];

inline void add(int u,int v,int p,int *head=::head){
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int bcc[N],tot;
int clk,pre[N],low[N];
stack<int> S;
#define U G[p].u
#define V G[p].v

inline void Tarjan(int u,int fa){
  pre[u]=low[u]=++clk; S.push(u);
  for (int p=head[u];p;p=G[p].next){
    if (p==(fa^1)) continue;
    if (!pre[V]){
      Tarjan(V,p);
      low[u]=min(low[u],low[V]);
      if (low[V]>pre[u]){
	++tot;
	while (S.top()!=V)
	  bcc[S.top()]=tot,S.pop();
	bcc[S.top()]=tot,S.pop();
	tag[p]=1;
      }
    }else
      low[u]=min(low[u],pre[V]);
  }
}

int eular[N<<2],back[N];
int tid[N],depth[N];

namespace ST{
  inline int Min(int a,int b){  
    return depth[a]<depth[b]?a:b;  
  }  
  const int K=25;
  int Log[N<<2];
  int st[N<<2][K];
  inline void Pre(int n,int *a){
    for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    for (int i=1;i<=n;i++) st[i][0]=a[i];
    for (int k=1;k<=Log[n];k++)
      for (int i=1;i<=n;i++){
	st[i][k]=st[i][k-1];
	if (i+(1<<(k-1))<=n)
	  st[i][k]=Min(st[i][k],st[i+(1<<(k-1))][k-1]);
      }
  }
  inline int Query(int l,int r){
    if (l>r) swap(l,r);  
    int t=Log[r-l+1];
    return Min(st[l][t],st[r-(1<<t)+1][t]);
  }
}

int root[N],troot;

inline void dfs(int u,int fa){
  root[u]=troot;
  tid[u]=++clk; eular[++*eular]=u; back[u]=*eular; depth[u]=depth[fa]+1;
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa)
      dfs(V,u),eular[++*eular]=u;
}

inline int LCA(int u,int v){
  return ST::Query(back[u],back[v]);
}

int n,m,Q;

int in,im;
int ps[N],us[N],vs[N];
int lst[N<<2],pnt;

bool cmp(int a,int b){
  return tid[a]<tid[b];
}

int Stack[N<<2],top;


int ibcc[N],itot;
int iclk,ipre[N],ilow[N];

inline void iTarjan(int u,int fa){
  ipre[u]=ilow[u]=++iclk; S.push(u);
  for (int p=head[u];p;p=G[p].next){
    if (p==(fa^1)) continue;
    if (!ipre[V]){
      iTarjan(V,p);
      ilow[u]=min(ilow[u],ilow[V]);
      if (ilow[V]>ipre[u]){
	++itot;
	while (S.top()!=V)
	  ibcc[S.top()]=itot,S.pop();
	ibcc[S.top()]=itot,S.pop();
      }
    }else
      ilow[u]=min(ilow[u],ipre[V]);
  }
}

int main(){
  int iu,iv; int R=0;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(Q); head=head1;
  for (int i=1;i<=m;i++)
    read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
  for (int i=1;i<=n;i++)
    if (!pre[i]){
      Tarjan(i,0);
      if (!S.empty()){
	++tot;
	while (!S.empty())
	  bcc[S.top()]=tot,S.pop();
      }
    }
  int tmp=inum;
  for (int p=2;p<=tmp;p++)
    if (tag[p])
      add(bcc[U],bcc[V],++inum,head2),add(bcc[V],bcc[U],++inum,head2);
  head=head2;
  clk=0;
  for (int i=1;i<=tot;i++)
    if (!tid[i])
      troot=i,dfs(i,0);
  ST::Pre(*eular,eular);
  tmp=inum;
  head=head3;
  for (int T=1;T<=Q;T++){
    read(in); read(im); pnt=0;
    for (int i=1;i<=in;i++){
      read(ps[i]); ps[i]=(ps[i]+R-1)%n+1,ps[i]=bcc[ps[i]];
      lst[++pnt]=ps[i];
    }
    for (int i=1;i<=im;i++){
      read(us[i]),read(vs[i]); us[i]=(us[i]+R-1)%n+1,vs[i]=(vs[i]+R-1)%n+1;
      us[i]=bcc[us[i]],vs[i]=bcc[vs[i]],lst[++pnt]=us[i],lst[++pnt]=vs[i];
    }
    sort(lst+1,lst+pnt+1,cmp);
    pnt=unique(lst+1,lst+pnt+1)-lst-1;
    
    for (int l=1,r;l<=pnt;l=r+1){
      r=l; while (r<pnt && root[lst[r+1]]==root[lst[r]]) r++;
      top=0; Stack[++top]=root[lst[l]];
      for (int i=l;i<=r;i++){
	int now=lst[i],lca=LCA(now,Stack[top]);
	while(1){
	  if(depth[lca]>=depth[Stack[top-1]]){
	    add(lca,Stack[top],++inum),add(Stack[top],lca,++inum);
	    top--;
	    if (Stack[top]!=lca) Stack[++top]=lca;
	    break;
	  }
	  add(Stack[top-1],Stack[top],++inum); add(Stack[top],Stack[top-1],++inum); top--;
	}
	if (Stack[top]!=now) Stack[++top]=now;
      }
      while (--top) add(Stack[top],Stack[top+1],++inum),add(Stack[top+1],Stack[top],++inum);
    }
    
    for (int i=1;i<=im;i++)
      add(us[i],vs[i],++inum),add(vs[i],us[i],++inum);
    for (int i=1;i<=pnt;i++)
      if (!ipre[lst[i]]){
	iTarjan(lst[i],0);
	if (!S.empty()){
	  ++itot;
	  while (!S.empty())
	    ibcc[S.top()]=itot,S.pop();
	}
      }
    int flag=1;
    for (int i=2;i<=in && flag;i++)
      if (ibcc[ps[i]]!=ibcc[ps[1]])
	flag=0;
    flag?((R+=T)%=n,printf("YES\n")):printf("NO\n");    
    for (int p=tmp+1;p<=inum;p++)
      head3[U]=ipre[U]=ilow[U]=ibcc[U]=0,head3[V]=ipre[V]=ilow[V]=ibcc[V]=0;
    inum=tmp; iclk=0; itot=0;
  }
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值