[cf1217F]Forced Online Queries Problem

可以用并查集维护连通性,删除可以用按置合并并查集,但删掉一条边后无法再维护两点的联通性了(因为产生环的边是不加入的)
暴力思路是, 考虑前i个操作后边的集合,暴力加入即可,但复杂度是$o(n^2)$的
用分块,对于每一个块,先求出前面所有块操作后边的集合,去掉这个块内删掉的边,这个并查集一定是之后这个块内每一个点都有的并查集,即计算每一个点时都恢复到这个并查集(恢复时记录下修改的点,因此也不能路径压缩)
之后用暴力的做法,这个集合大小是$o(\sqrt{n})$的,那么总复杂度就是$o(n\sqrt{n})$,可以通过
(这个算法是离线,因为它需要之后那个块内的操作,但这些操作最多只会衍生出两种操作,只要存在一个就都不要放入原并查集中即可)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define K 5000
 4 #define N 200005
 5 #define pii pair<int,int>
 6 #define fi first
 7 #define se second
 8 int n,m,ans,p[N],x[N],y[N],f[N],g[N],sz[N],v1[N];
 9 pii v2[N];
10 set<pii>g1,g2;
11 set<pii>::iterator it;
12 int find(int k){
13     if (k==f[k])return k;
14     return find(f[k]);
15 }
16 void check(int x,int y){
17     if (x>y)swap(x,y);
18     pii o=make_pair(x,y);
19     if (g1.find(o)!=g1.end()){
20         g1.erase(o);
21         g2.insert(o);
22     }
23 }
24 void update(pii o){
25     if (g2.find(o)==g2.end())g2.insert(o);
26     else g2.erase(o);
27 }
28 void add(int x,int y){
29     x=find(x);
30     y=find(y);
31     if (x==y)return;
32     if (sz[x]<sz[y])swap(x,y);
33     v1[++v1[0]]=y;
34     f[y]=x;
35     v2[v1[0]]=make_pair(x,sz[x]);
36     sz[x]=max(sz[x],sz[y]+1);
37 }
38 int main(){
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=m;i++)scanf("%d%d%d",&p[i],&x[i],&y[i]);
41     for(int i=1;i<=m;i+=K){
42         int k=min(m,i+K-1);
43         g2.clear();
44         for(int j=i;j<=k;j++)
45             if (p[j]==1){
46                 check(x[j],y[j]);
47                 check(x[j]%n+1,y[j]%n+1);
48             }
49         for(int j=1;j<=n;j++)f[j]=j;
50         for(it=g1.begin();it!=g1.end();it++)add((*it).fi,(*it).se);
51         v1[0]=0;
52         for(int j=i;j<=k;j++){
53             x[j]=(x[j]+ans-1)%n+1;
54             y[j]=(y[j]+ans-1)%n+1;
55             if (x[j]>y[j])swap(x[j],y[j]);
56             if (p[j]==1)update(make_pair(x[j],y[j]));
57             else{
58                 for(int l=1;l<=v1[0];l++){
59                     f[v1[l]]=v1[l];
60                     sz[v2[l].fi]=v2[l].se;
61                 }
62                 v1[0]=0;
63                 for(it=g2.begin();it!=g2.end();it++)add((*it).fi,(*it).se);
64                 printf("%d",ans=(find(x[j])==find(y[j])));
65             }
66         }
67         for(it=g2.begin();it!=g2.end();it++)g1.insert(*it);
68     }
69 }
View Code

 

转载于:https://www.cnblogs.com/PYWBKTDA/p/11561274.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值