树状数组求第k大值
思路有一点想ST表
将求第k大变为求第(tot-k+1)小的数,tr[i]统计小于等于i的数的总数
每次不断逼近,若当前[ans,ans+(1<<i)]在范围内,则加上,否则直接到下一次循环
过程中的一个地方要注意(详见代码注释)
#include<cstdio> #include<cctype> using namespace std; int n,m,fa[200002],tr[200002],siz[200002]; inline void read(int &x){ char ch=getchar();x=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} } inline int findfa(int x){ if(fa[x]==x)return x;return fa[x]=findfa(fa[x]); } inline void updata(int now,int ad){ for(;now<=n;now+=now&-now)tr[now]+=ad; } inline int query(int k){ int cnt=0,ans=0; for(int i=20;i>=0;i--){ ans+=1<<i; if(ans>n||cnt+tr[ans]>=k)ans-=1<<i;else cnt+=tr[ans];//这里if语句中一定的是<=,否则若存在多个与k大数相同的数就会存在漏洞 } return ans+1; } int main(){ read(n);read(m); int tot=n; for(int i=1;i<=n;i++){siz[i]=1;fa[i]=i;} updata(1,n); while(m--){ int c,x,y; read(c); switch(c){ case 0:{ read(x);read(y);int fx=findfa(x),fy=findfa(y); if(fx==fy)continue; updata(siz[fx],-1);updata(siz[fy],-1); siz[fy]+=siz[fx];updata(siz[fy],1);fa[fx]=fy;tot--; break;} case 1:read(x);printf("%d\n",query(tot-x+1));break; } } }