正题
题目大意
有若干个事件
- Kc:cK\ c:cK c:c值更改并且清除生气状态
- Rxy:R\ x\ y:R x y:新建一条x′x'x′到y′y'y′的边,若当前处于生气状态则x=(x′+n−c)%n,y=(y′+n−c)%nx=(x'+n-c)\%n,y=(y'+n-c)\%nx=(x′+n−c)%n,y=(y′+n−c)%n,否则x=x′,y=y′x=x',y=y'x=x′,y=y′
- Txyt:T\ x\ y\ t:T x y t:询问从xxx到yyy是否现在可行并且修建ttt条路之前不可行,输出结果。且若可行清除生气状态,否则进入生气状态。
解题思路
使用并查集判断是否联通,并且不使用路径压缩。
用timxtim_xtimx表示由faxfa_xfax到xxx这跳边是何时建立的,那我们询问时若询问的时间点time>timxtime>tim_xtime>timx就不继续往后跳即可。
但是这要会TLETLETLE,所以我们按秩合并,由小的合并到大的上。
这要因为每个的最多被合并lognlog\ nlog n次所以时间复杂度为:O(nlogn):O(n\ log\ n):O(n log n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=300100;
int n,m,fa[N],tim[N],siz[N],c,angry,cnt;
int find(int x,int t)
{if(fa[x]==x||tim[x]>t) return x;return find(fa[x],t);
}
int main()
{freopen("data.out","w",stdout);scanf("%d%d",&n,&m);for(int i=0;i<n;i++)fa[i]=i,siz[i]=1;while(m--){char op[3];int x,y,t;scanf("%s",op);if(op[0]=='K')angry=0,scanf("%d",&c);if(op[0]=='R'){scanf("%d%d",&x,&y);++cnt;if(angry) x=(x+c)%n,y=(y+c)%n;x=find(x,cnt);y=find(y,cnt);if(x==y) continue;if(siz[x]<siz[y])fa[x]=y,tim[x]=cnt,siz[y]+=siz[x];elsefa[y]=x,tim[y]=cnt,siz[x]+=siz[y];}if(op[0]=='T'){scanf("%d%d%d",&x,&y,&t);if(find(x,cnt)==find(y,cnt)&&find(x,cnt-t)!=find(y,cnt-t))angry=0,printf("Y\n");else angry=1,printf("N\n");}}
}