题目:
分析:
求历史两个点之间是否连通->可持久化并查集。
注意:点的标号从0开始,主席树的范围应该是:0~n-1
#include<bits/stdc++.h> using namespace std; #define mid ((l+r)>>1) #define N 9000005 int ndnum=0,lc[N],rc[N],fa[N],dep[N],ed[N],n,m; void build(int s,int l,int r) { if(l==r) { fa[s]=l; return ; } build(lc[s]=++ndnum,l,mid); build(rc[s]=++ndnum,mid+1,r); } void modify(int s,int l,int r,int pos) { if(l==r) { dep[s]++; return ; } if(pos<=mid) modify(lc[s],l,mid,pos); else modify(rc[s],mid+1,r,pos); } int query(int s,int l,int r,int pos) { if(l==r) return s; if(pos<=mid) return query(lc[s],l,mid,pos); else return query(rc[s],mid+1,r,pos); } void merge(int last,int &rt,int l,int r,int pos,int f) { rt=++ndnum; lc[rt]=lc[last]; rc[rt]=rc[last]; if(l==r) { fa[rt]=f; dep[rt]=dep[last]; return ; } if(pos<=mid) merge(lc[last],lc[rt],l,mid,pos,f); else merge(rc[last],rc[rt],mid+1,r,pos,f); } int get_fa(int s,int pos) { int now=query(s,0,n-1,pos); if(fa[now]==pos) return now; return get_fa(s,fa[now]); } char op[5]; int main() { freopen("history.in","r",stdin); freopen("history.out","w",stdout); int v,x,y,c=0,t,fl=0; scanf("%d%d",&n,&m); build(ed[0]=++ndnum,0,n-1); int i=0; while(m--){ scanf("%s",op); if(op[0]=='K') scanf("%d",&v),c=v,fl=0;//注意题意:换国王之后就不生气了 if(op[0]=='R'){ i++; ed[i]=ed[i-1]; scanf("%d%d",&x,&y); if(fl) x=(x+c)%n,y=(y+c)%n; int f1=get_fa(ed[i],x),f2=get_fa(ed[i],y); if(fa[f1]==fa[f2]) continue; if(dep[f1]>dep[f2]) swap(f1,f2); merge(ed[i-1],ed[i],0,n-1,fa[f1],fa[f2]); if(dep[f1]==dep[f2]) modify(ed[i],0,n-1,fa[f2]); } if(op[0]=='T'){ scanf("%d%d%d",&x,&y,&t); int f1=get_fa(ed[max(0,i-t)],x),f2=get_fa(ed[max(0,i-t)],y); int f3=get_fa(ed[i],x),f4=get_fa(ed[i],y); if(fa[f1]!=fa[f2]&&fa[f3]==fa[f4]) printf("Y "),fl=0; else printf("N "),fl=1; } } return 0; } /* 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 */