可以说是线段树合并的裸题吧
题意就是给你两个操作
一个操作是合并两个集合,这两个集合都是用权值线段树维护的,便于查询第k小元素
另一个操作就是查询区间极值了
1 #include<cstdio> 2 const int maxn=100005; 3 int n,m,sz; 4 int v[maxn],id[maxn],fa[maxn],root[maxn]; 5 int lch[1800000],rch[1800000],sum[1800000]; 6 inline int read() 7 { 8 int x=0,f=1;char ch=getchar(); 9 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 10 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 11 return x*f; 12 } 13 int find(int x) 14 { 15 return x==fa[x]?x:fa[x]=find(fa[x]); 16 } 17 void insert(int &k,int l,int r,int val) 18 { 19 if(k==0) k=++sz; 20 if(l==r) 21 { 22 sum[k]=1;return; 23 } 24 int mid=(l+r)>>1; 25 if(val<=mid) insert(lch[k],l,mid,val); 26 else insert(rch[k],mid+1,r,val); 27 sum[k]=sum[lch[k]]+sum[rch[k]]; 28 } 29 int query(int k,int l,int r,int rank) 30 { 31 if(l==r) return l; 32 int mid=(l+r)>>1; 33 if(sum[lch[k]]>=rank) return query(lch[k],l,mid,rank); 34 else return query(rch[k],mid+1,r,rank-sum[lch[k]]); 35 } 36 int merge(int x,int y) 37 { 38 if(x==0) return y; 39 if(y==0) return x; 40 lch[x]=merge(lch[x],lch[y]); 41 rch[x]=merge(rch[x],rch[y]); 42 sum[x]=sum[lch[x]]+sum[rch[x]]; 43 return x; 44 } 45 int main() 46 { 47 n=read();m=read(); 48 for(int i=1;i<=n;i++) v[i]=read(); 49 for(int i=1;i<=n;i++) fa[i]=i; 50 int x,y; 51 for(int i=1;i<=m;i++) 52 { 53 x=read(),y=read(); 54 int p=find(x),q=find(y); 55 fa[p]=q; 56 } 57 for(int i=1;i<=n;i++) 58 { 59 insert(root[find(i)],1,n,v[i]); //往对应的线段树插点 60 id[v[i]]=i; 61 } 62 int k=read(); 63 char ch[2]; 64 while(k--) 65 { 66 scanf("%s",ch); 67 x=read();y=read(); 68 if(ch[0]=='Q') 69 { 70 int p=find(x); 71 if(sum[root[p]]<y) 72 { 73 puts("-1");continue;//查询越界 74 } 75 int t=query(root[p],1,n,y); //得到location 76 printf("%d ",id[t]); 77 } 78 else 79 { 80 int p=find(x),q=find(y); 81 if(p!=q) 82 { 83 fa[p]=q; 84 root[q]=merge(root[p],root[q]); 85 } 86 } 87 } 88 return 0; 89 }
权值线段树的理解更加深刻了
权值线段树的下标是数字本身,而存的是这个数出现的次数,也就是权值
一般权值线段树都是和动态开点捆绑在一起的
所谓动态开点,就是每个节点用的时候再开,可以去掉许多无用的节点
和主席树的区别,目前阶段的理解就是,主席树需要离散化,动态开点线段树不需要?
建n棵线段树,每一棵线段树维护[1,i]的数字出现情况
也就是当前数字范围内的数出现了多少次
然后前缀和查找就好了
可以这么说,动态开点的权值线段树的儿子之间没有耦合,可持久化权值线段树的儿子之间是耦合在一起的
虽然功能一样的,但是T和M会有差异