Description
在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道“这里真是个迷人的绿色世界,空气清新、淡雅,到处散发着醉人的奶浆味;小猴在枝头悠来荡去,好不自在;各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果;鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境” SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树,动态仙人掌了,那么今天就来见识一下动态图吧” LJJ:“要支持什么操作?” SHY:“ 1.新建一个节点,权值为x。 2.连接两个节点。 3.将一个节点a所属于的联通快内权值小于x的所有节点权值变成x。 4.将一个节点a所属于的联通快内权值大于x的所有节点权值变成x。 5.询问一个节点a所属于的联通块内的第k小的权值是多少。 6.询问一个节点a所属联通快内所有节点权值之积与另一个节点b所属联通快内所有节点权值之积的大小。 7.询问a所在联通快内节点的数量
Input
第一行有一个正整数m,表示操作个数。 接下来m行,每行先给出1个正整数c。
若c=1,之后一个正整数x,表示新建一个权值为x的节点,并且节点编号为n+1(当前有n个节点)。
若c=2,之后两个正整数a,b,表示在a,b之间连接一条边。
若c=3,之后两个正整数a,x,表示a联通快内原本权值小于x的节点全部变成x。
若c=4,之后两个正整数a,x,表示a联通快内原本权值大于x的节点全部变成x。
若c=5,之后两个正整数a,k,表示询问a所属于的联通块内的第k小的权值是多少。
若c=6,之后两个正整数a,b,表示询问a所属联通快内所有节点权值之积与b所属联通快内所有节点权值之积的大小, 若a所属联通快内所有节点权值之积大于b所属联通快内所有节点权值之积,输出1,否则为0。
若c=7,之后一个正整数a,表示询问a所在联通块大小
HINT
对100%的数据 0<=m<=400000,c<=7,所有出现的数均<=1000000000,所有出现的点保证存在
对每个连通块维护一棵平衡树
操作2启发式合并,操作3,4可以打标记,操作6用对数(可能会被卡精度但随机数据基本正确,也没有其他好的方法)
线段树会被卡空间,随机数据总体时间也比平衡树慢,但极限数据操作1较少还是可以卡过去
#include<cstdio> #include<cmath> #include<cstdlib> inline int _int(){ int x=0,c=getchar(); while(c>57||c<48)c=getchar(); while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x; } const int N=400010; int ch[N][2],sz[N],rnd[N],val[N],col[N],ptr=0,stk[N],rt[N],stp=0; int vc[N]; double lgv[N],lgs[N]; void up(int w){ sz[w]=1+sz[ch[w][0]]+sz[ch[w][1]]; lgs[w]=lgv[w]+lgs[ch[w][0]]+lgs[ch[w][1]]; } void dn(int w){ if(!vc[w])return; if(int u=ch[w][0]){ vc[u]=val[u]=vc[w]; lgs[u]=(lgv[u]=lgv[w])*sz[u]; } if(int u=ch[w][1]){ vc[u]=val[u]=vc[w]; lgs[u]=(lgv[u]=lgv[w])*sz[u]; } vc[w]=0; } void dfs(int w){ if(!w)return; stk[stp++]=w; dn(w); dfs(ch[w][0]); dfs(ch[w][1]); } void rot(int&w,int d){ int u=ch[w][d]; ch[w][d]=ch[u][d^1]; ch[u][d^1]=w; up(w); up(w=u); } void ins(int&w,int v){ if(w){ ++sz[w];lgs[w]+=lgv[v]; dn(w); int d=(val[w]<val[v]); int&u=ch[w][d]; ins(u,v); if(rnd[u]>rnd[w])rot(w,d); }else w=v; } int kmin(int w,int k){ --k; while(1){ dn(w); int s=sz[ch[w][0]]; if(s>k)w=ch[w][0]; else if(s<k)k-=s+1,w=ch[w][1]; else return val[w]; } } void setmin(int w,int x){ if(!w)return; dn(w); if(val[w]<=x){ val[w]=x; lgv[w]=log(x); if(int u=ch[w][0]){ vc[u]=val[u]=x; lgs[u]=(lgv[u]=log(x))*sz[u]; } setmin(ch[w][1],x); }else setmin(ch[w][0],x); up(w); } void setmax(int w,int x){ if(!w)return; dn(w); if(val[w]>=x){ val[w]=x; lgv[w]=log(x); if(int u=ch[w][1]){ vc[u]=val[u]=x; lgs[u]=(lgv[u]=log(x))*sz[u]; } setmax(ch[w][0],x); }else setmax(ch[w][1],x); up(w); } int main(){ srand(1844677); lgs[0]=0; for(int q=_int();q;q--) switch(_int()){ case 1:{ val[++ptr]=_int(); rt[ptr]=col[ptr]=ptr; sz[ptr]=1; lgs[ptr]=lgv[ptr]=log(val[ptr]); rnd[ptr]=rand(); break; } case 2:{ int a=col[_int()],b=col[_int()]; if(a!=b){ if(sz[rt[a]]<sz[rt[b]])a^=b,b^=a,a^=b; stp=0; dfs(rt[b]); for(int i=0;i<stp;i++){ int w=stk[i]; lgs[w]=lgv[w]; col[w]=a; sz[w]=1;ch[w][0]=ch[w][1]=0; ins(rt[a],w); } } break; } case 3:{ int a=col[_int()],x=_int(); setmin(rt[a],x); break; } case 4:{ int a=col[_int()],x=_int(); setmax(rt[a],x); break; } case 5:{ int a=col[_int()]; printf("%d\n",kmin(rt[a],_int())); break; } case 6:{ int a=rt[col[_int()]],b=rt[col[_int()]]; printf("%d\n",lgs[a]>lgs[b]); break; } case 7:{ printf("%d\n",sz[rt[col[_int()]]]); break; } } return 0; }