【JZOJ B组】【GDOI2016模拟3.11】历史

题目

FA♂Q

ass♂barket

DDF

思路

首先,我们可以选择暴力。用t(时间)个并查集维护每一个状态,每次查询随便搞搞即可。
但是很明显会MLE、TLE。

我们可以发现,每次加入一条边,只需更新一个点的father(不用路径压缩),而且,每个点只会更新一个father(用按质合并)。
所以我们可以考虑用一个year数组来记录那个点加入集合的时间,getfather的时候判断当前点是否在当前时间之间加入集合。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=300077;
int v=0,yr=0,f[maxn],year[maxn],z[maxn],n,m;
bool is_mad=0;
char c[2];
int gf(int x,int t)
{
    while(x!=f[x]&&year[x]<=t) x=f[x];
    return x;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
    {
        f[i]=i; z[i]=1;
    }
    while(m--)
    {
        scanf("%s",c);
        if(c[0]=='K')
        {
            scanf("%d",&v); is_mad=0;
        }else
        if(c[0]=='R')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(is_mad)
            {
                if((x+=v)>=n) x-=n;
                if((y+=v)>=n) y-=n;
            }
            yr++;
            x=gf(x,yr); y=gf(y, yr);
            if(x==y) continue;
            if(z[x]<z[y]) 
            {
                f[x]=y; z[y]+=z[x]; year[x]=yr;
            }
            else 
            {
                f[y]=x; z[x]+=z[y]; year[y]=yr;
            }
        }else
        if(c[0]=='T')
        { 
            int st,ed,t;
            scanf("%d%d%d",&st,&ed,&t);
            if(is_mad=((gf(st,yr-t)==gf(ed,yr-t))||(gf(st,yr)^gf(ed,yr)))) printf("N\n");
            else printf("Y\n");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/81070015