码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 72 F. Forced Online Queries Problem

时间:2019-09-11 21:43:23      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:putchar   超过   codeforce   pen   思路   last   line   次数   大小   

题目梗概

有一张\(n\)个点的图,刚开始没有边,现在又两种操作,一种是加入一条边(如果这条边存在,否则删去这条边),一种是询问\(x,y\)是否联通。

\(x,y\)给出的形式是\((x+last-1)%n+1\),\((y+last-1)%n+1\),\(last\)为上一次询问的答案。

解题思路

对于这题的离线版本有两种写法:线段树分治,以及对操作分块。

线段树分治的做法比较常见,下面来讲讲分块的做法。

对于当前块之前的操作,我们可以找出哪些边在当前块需要操作,设为集合\(B\),当然就有不需要操作的边,设为集合\(C\)

对于集合\(C\)我们可以提前建好边,然后对于当前块的操作:如果是修改,那么直接修改集合\(B\);如果是询问,就往集合\(C\)暴力加入集合\(B\)的边,然后查询。

因为集合\(C\)的构建次数不超过\(m/P\),集合\(B\)的大小不超过\(P\),所以复杂度为\(m\sqrt mlogm\)

那么回到这道题,分块的做法十分的显然,集合\(B\)的定义改成可能操作的边的集合即可。

其实线段树分治也是可以的,因为分治的过程也是按时间顺序,我们考虑这条边可能加入的位置。

如果这条边是第奇数次确定加入,那么就可以贡献到下次可能出现的位置,直到某个位置也确定加入(即删除)。

#include<set>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define pr pair<int,int>
#define mk make_pair
#define fr first
#define sc second
#define IT set<pr>::iterator
using namespace std;
const int maxn=400005;
inline int _read(){
    int num=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
    return num;
}
struct jz{
    int x,y;
    jz(int x=0,int y=0):x(x),y(y){}
}S[maxn];
set<pr> A,B,C;
void add(set<pr> &S,pr x){if (S.find(x)==S.end()) S.insert(x);else S.erase(x);}
int n,m,L,R,K,ans[maxn],tg[maxn],tim,top,s[maxn],f[maxn];
pr ed[maxn][2];
int get(int x){if (f[x]==x) return x;return get(f[x]);}
void merge(int x,int y){
    x=get(x);y=get(y);if (x==y) return;
    if (s[x]<s[y]) swap(x,y);S[++top]=jz(x,y);
    s[x]+=s[y];f[y]=x;
}
void Back(int t){
    while(top!=t){
        int x=S[top].x,y=S[top].y;
        f[y]=y;s[x]-=s[y];top--;
    }
}
void add(pr h){merge(h.fr,h.sc);} 
void Build(){
    for (int i=1;i<=n;i++) f[i]=i,s[i]=1;top=0;
    for (IT i=C.begin();i!=C.end();i++) add(*i);tim=top;
}
int ask(pr h){return get(h.fr)==get(h.sc);}
int main(){
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    n=_read();m=_read();K=sqrt(2*m*log(m));
    for (int j=1;j<=m;j+=K){
        L=j;R=min(m,L+K-1);A.clear();B.clear();C.clear();
        for (int i=L;i<=R;i++){
            tg[i]=_read();int x=_read(),y=_read();
            if (x>y) swap(x,y);ed[i][0]=mk(x,y);
            x=x%n+1;y=y%n+1;
            if (x>y) swap(x,y);ed[i][1]=mk(x,y);
            if (tg[i]==1) A.insert(ed[i][0]),A.insert(ed[i][1]);
        }
        for (int i=1;i<L;i++) if (tg[i]==1){
            if (A.find(ed[i][ans[i]])==A.end()) add(C,ed[i][ans[i]]);else add(B,ed[i][ans[i]]);
        }
        Build();
        for (int i=L;i<=R;i++)
        if (tg[i]==1) ans[i]=ans[i-1],add(B,ed[i][ans[i]]);else{
            Back(tim);for (IT t=B.begin();t!=B.end();t++) add(*t);
            ans[i]=ask(ed[i][ans[i-1]]);
        }
    }
    for (int i=1;i<=m;i++) if (tg[i]==2) putchar(ans[i]+'0');
    return 0;
}

Educational Codeforces Round 72 F. Forced Online Queries Problem

标签:putchar   超过   codeforce   pen   思路   last   line   次数   大小   

原文地址:https://www.cnblogs.com/CHNJZ/p/11508728.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!