7.19T3
小 X 的图
题目背景及题意
小 X 有一张图,有 n 个点(从 0 开始编号),一开始图里并没有
边,他有时候会向其中添加一条双向边(x 到 y)。小 X 会时不时想知
道某两个点是否联通,如果连通并在 t 次加边操作之前不连通,他就
会对自己加的边感到满意,否则他就会生气,并会错误地记录接下来
添加的边,将 x 记录为(x+n-c)%n ,y 记录为(y+n-c)%n。直到
他下一次询问为止。C 是一个小 X 随意定的值(一开始是 0),当然也
会随他意愿修改。
你的任务就是回答他的每一次询问
输入格式
第一行 n,m,表示点的个数和小 X 操作的总数
接下来 m 行,每行先是一个字符
“K”:接下来一个数字 c,表示小 X 新的 c 值
“R”:接下来两个整数 u,v,表示连一条双向边
“T”:接下来三个整数 u,v,t,表示询问 u 到 v 的连通性,t 的意
义上文已经提到过了
保证:无自环(但有重边
输出格式
对于每个询问输出一行“Y”代表小 X 满意,“N”代表小 X 生气
样例数据 详见 sample 文件夹
数据范围
对于 30%的数据 n<=1000,m<=3000
对于剩余数据:n , m<=300000
对于所有数据:0<=t<=m(但有可能向前第 t 次加边不存在
提示:做完这题你就 AK 了,是不是很开心呢
sol:这大概就是一道可持久化并查集裸题。虽然300000两只log看上去有点不可过,但就是过了。。。
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();} while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();} return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) {putchar('-'); x=-x;} if(x<10) {putchar(x+'0'); return;} write(x/10); putchar((x%10)+'0'); } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=300005; inline void copy(int &x,int y,int l,int r); inline void Build(int &x,int l,int r); inline void Chag(int &x,int y,int l,int r,int Pos,int Val); inline int Que(int x,int l,int r,int Pos); int n,m,cnt=0,Now; int fa[N],sz[N]; vector<int>Jh[N]; int rt[N<<2]; #define PB push_back struct Node { int ls,rs,id; }T[N*105]; inline int gf(int x){return (x==fa[x])?(x):(fa[x]=gf(fa[x]));} inline void ubbon(int x,int y) { int i,xx=gf(x),yy=gf(y); if(xx==yy) { // cout<<"@@@@@"<<x<<' '<<y<<endl; copy(rt[Now],rt[Now-1],1,n); return; } if(sz[xx]<sz[yy]) swap(xx,yy); fa[yy]=xx; sz[xx]+=sz[yy]; int oo[2],t=0; copy(oo[t],rt[Now-1],1,n); for(i=0;i<Jh[yy].size();i++) { t^=1; oo[t]=0; Chag(oo[t],oo[t^1],1,n,Jh[yy][i],xx); Jh[xx].PB(Jh[yy][i]); } copy(rt[Now],oo[t],1,n); Jh[yy].clear(); } inline void Build(int &x,int l,int r) { x=++cnt; if(l==r) { T[x].id=l; return; } int mid=(l+r)>>1; Build(T[x].ls,l,mid); Build(T[x].rs,mid+1,r); } inline void copy(int &x,int y,int l,int r) { x=y; } inline void Chag(int &x,int y,int l,int r,int Pos,int Val) { x=++cnt; T[x]=T[y]; if(l==r) { T[x].id=Val; return; } int mid=(l+r)>>1; if(Pos<=mid) Chag(T[x].ls,T[y].ls,l,mid,Pos,Val); else Chag(T[x].rs,T[y].rs,mid+1,r,Pos,Val); } inline int Que(int x,int l,int r,int Pos) { if(l==r) return T[x].id; int mid=(l+r)>>1; if(Pos<=mid) return Que(T[x].ls,l,mid,Pos); else return Que(T[x].rs,mid+1,r,Pos); } int main() { freopen("history.in","r",stdin); freopen("history.out","w",stdout); int i,C=0,x,y,z,Last; char S[5]; R(n); R(m); for(i=1;i<=n;i++) {fa[i]=i; sz[i]=1; Jh[i].PB(i);} Build(rt[Now=0],1,n); // for(i=1;i<=n;i++) cout<<Que(rt[Now],1,n,i)<<' '; // putchar('\n'); int Test=0; while(m--) { scanf("%s",S+1); switch (S[1]) { case 'K': R(C); break; case 'R': R(x); R(y); x=(x+Last*C)%n; y=(y+Last*C)%n; x++; y++; // cout<<"RRR"<<' '<<x<<' '<<y<<endl; Now++; ubbon(x,y); break; case 'T': R(x); R(y); R(z); x++; y++; if(x==y) {puts("N"); Last=1; break;} int xx=gf(x),yy=gf(y); if(xx==yy) { if(Now<z) puts("Y"),Last=0; else { int c1=Que(rt[Now-z],1,n,x),c2=Que(rt[Now-z],1,n,y); if(c1==c2) puts("N"),Last=1; else puts("Y"),Last=0; } } else puts("N"),Last=1; // if(++Test==185) return 0; break; } // for(i=1;i<=n;i++) cout<<Que(rt[Now],1,n,i)<<' '; // putchar('\n'); } return 0; }
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!