【GDOI2016模拟3.11】历史
Description
Input
Output
Sample Input
3 7
R 0 1
T 0 1 1
K 1
R 0 1
T 0 1 1
R 0 1
T 0 2 1
Sample Output
Y
N
Y
Data Constraint
.
.
.
.
.
分析
【简洁且能够处理询问也强制在线的情况】
30%做法:暴力存下每次的并查集。复杂度O(nm)。
70%做法:熟悉数据结构的同学应该很容易想到这个做法。这道题显然可以用可持久化并查集维护,用按秩合并套上一个可持久化线段树维护fa数组。复杂度O(nlog2n),由于数据有梯度,这个做法本地测试时给了70%的分数。但是要是又遇到跑得十分快的评测机,那我也是没办法了。/微笑/微笑/微笑
100%做法:实际上我们并没有基于历史来修改fa数组,而只是基于历史查询,所以并不需要使用真正的可持久化。考虑套用上做法一,在并查集的边上存下这条边建立的时间。查询时查询一下到并查集的根这条路径的最小值即可知道两个结点连通的时间。复杂度O(nlogn),可以拿到100%的分数。
.
.
注意:要读入优化!
.
.
.
.
.
程序:
#include<iostream>
#include<stdio.h>
using namespace std;
int f[300001],sz[300001],year[300001],n,m,x,y,t,c=0,yr=0;
char zf[3];
bool bz=false;
inline void read(int &x)
{
x=0;
char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9')
{
x=x*10+c-'0';
c=getchar();
}
}
int find(int x, int t)
{
while (x!=f[x]&&year[x]<=t) x=f[x];
return x;
}
int main()
{
read(n);
read(m);
for (int i=0;i<n;i++)
{
f[i]=i;
sz[i]=1;
}
while (m--)
{
scanf("%s",&zf);
if (zf[0]=='K')
{
read(c);
bz=false;
continue;
}
if (zf[0]=='R')
{
read(x);
read(y);
if (bz==true)
{
if ((x+=c)>=n) x-=n;
if ((y+=c)>=n) y-=n;
}
yr++;
x=find(x,yr);
y=find(y,yr);
if (x==y) continue;
if (sz[x]<sz[y])
{
f[x]=y;
sz[y]+=sz[x];
year[x]=yr;
} else
{
f[y]=x;
sz[x]+=sz[y];
year[y]=yr;
}
continue;
}
if (zf[0]=='T')
{
read(x);read(y);read(t);
if (bz=((find(x,yr-t)==find(y,yr-t))||(find(x,yr)^find(y,yr)))) printf("N\n"); else printf("Y\n");
}
}
return 0;
}