B题:
比赛的时候我又没仔细看题,又把题目读错了。。。虽然读对的话我也不一定能想出如何用加权并查集做。比赛的时候我的第一感觉就是splay模拟,赛后写了一下,TLE了。。。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define key_val ch[ch[rt][1]][0] using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,q; char op[10];int x,y; int node[maxn];/// node[x] x所在结点 ///--- splay int pre[maxn],ch[maxn][2]; int val[maxn]; int sz[maxn]; int tot1,s[maxn],tot2; void newnode(int &x,int fa,int k) { if(tot2) x=s[tot2--]; else x=++tot1; pre[x]=fa; val[x]=k; sz[x]=1; MS0(ch[x]); } void up(int x) { sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; } void rot(int x,int kind) { int y=pre[x]; ch[y][kind^1]=ch[x][kind]; pre[ch[x][kind]]=y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; up(y); } void splay(int x,int goal) { while(pre[x]!=goal){ if(pre[pre[x]]==goal) rot(x,ch[pre[x]][0]==x); else{ int y=pre[x],z=pre[y]; int kind=ch[y][0]==x,one=0; if(ch[y][0]==x&&ch[z][0]==y) one=1; if(ch[y][1]==x&&ch[z][1]==y) one=1; if(one) rot(y,kind),rot(x,kind); else rot(x,kind),rot(x,kind^1); } } up(x); } void Init_splay() { pre[0]=0; MS0(ch[0]); sz[0]=0; tot1=tot2=0; } void Init() { Init_splay(); int rt; REP(i,1,n) newnode(rt,0,i),node[i]=rt; } ///----solve int Calc(int x) { int y=node[x]; splay(y,0); return sz[ch[y][0]]; } void Put(int x,int y) { int z=node[x],w=node[y]; if(z==w) return; splay(z,0); while(ch[z][0]) z=ch[z][0]; splay(z,0); splay(w,0); ch[z][0]=w; pre[w]=z; splay(w,0); } int main() { freopen("in.txt","r",stdin); while(~scanf("%d",&q)){ n=30010; Init(); REP(i,1,q){ scanf("%s",op); if(op[0]=='M'){ scanf("%d%d",&x,&y); Put(x,y); } else{ scanf("%d",&x); printf("%d ",Calc(x)); } } } return 0; }
没办法,学并查集的思路吧,作为专搞数据结构的,这种加权并查集的题目没做出来实在惭愧。。
好了,我已经知道会这道题了,并不是我思维不行,实在是这是我做的第一道加权并查集的题目。加权并查集就是将x和fa[x]这条树边的边权存在x的点权中,查找路径压缩的时候先find再改边权,因为是往上寻找,所以从祖先开始往下更新,说的比较含糊,其实是很简单很容易理解的东西。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,q; int fa[maxn],sz[maxn],w[maxn]; char op[10];int x,y; int find(int x) { if(fa[x]==x) return x; int t=find(fa[x]); w[x]+=w[fa[x]]; return fa[x]=t; } void Union(int u,int v) { int x=find(u),y=find(v); if(x==y) return; fa[x]=y; w[x]=sz[y]; sz[y]+=sz[x]; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE while(~scanf("%d",&q)){ n=30010; REP(i,0,n) fa[i]=i,w[i]=0,sz[i]=1; while(q--){ scanf("%s",op); if(op[0]=='M') scanf("%d%d",&x,&y),Union(x,y); else scanf("%d",&x),find(x),printf("%d ",w[x]); } } return 0; } /** 10 M 1 6 M 2 4 M 2 6 M 6 5 C 1 C 2 C 3 C 4 C 5 C 6 5 M 1 6 M 2 4 M 2 6 M 6 5 C 2 */