[BZOJ4923]K小值查询
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4923]K小值查询相关的知识,希望对你有一定的参考价值。
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4923
好题啊!直接做肯定是不行的,我们需要发现一些性质。考虑减去k后对各个数的影响,对于(k,2k](即大于k小于等于2k)的数,它们被减后会小于等于k,但对于>2k的数,减去k后还是大于k的,且那些数的相对大小不变,因为要动态维护第k大,我们可以想到用平衡树,一般用splay,然后对于(k,2k]的数,直接暴力提取,一个个减去k,再暴力插入回去,大于2k的数直接打个标记就好了。我们分析下复杂度,(k,2k]的数至少会减少一半,那么对于每个数,减的次数,也就是插入的次数,最多是logn,总复杂度为nlognlogn
贴代码:
#include<cstdio> #include<algorithm> using namespace std; //-----------------------------------------------head-------------------------------------------// const int N=100010; typedef long long LL; const LL inf=1e18; int n,q,fa[N],c[N][2],siz[N],lazy[N],rt,s[N],top; LL a[N]; int Write[20]; inline int read() {int d=0,f=1; char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1; c=getchar();} while (c>=‘0‘&&c<=‘9‘) d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;} inline void write(int x){int t=0; if (x<0) putchar(‘-‘),x=-x; for (;x;x/=10) Write[++t]=x%10; if (!t) putchar(‘0‘); for (int i=t;i>=1;i--) putchar((char)(Write[i]+48));} inline void pushup(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;} inline void mark(int x,int v){if (!x) return;lazy[x]+=v;a[x]+=v;} inline void pushdown(int x){if (!lazy[x]) return; mark(c[x][0],lazy[x]);mark(c[x][1],lazy[x]);lazy[x]=0;} inline void build(int &k,int l,int r,int last) { if (l>r) return; k=(l+r)>>1; fa[k]=last; build(c[k][0],l,k-1,k); build(c[k][1],k+1,r,k); pushup(k); } inline void rotate(int x,int &k) { int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if (y==k) k=x; else c[z][c[z][1]==y]=x; fa[c[x][r]]=y; fa[y]=x; fa[x]=z; c[y][l]=c[x][r]; c[x][r]=y; pushup(y); pushup(x); } inline void splay(int x,int &k) { while (x!=k) { int y=fa[x],z=fa[y]; if (y!=k) if (c[y][0]==x^c[z][0]==y) rotate(x,k); else rotate(y,k); rotate(x,k); } } inline int find(int x,int k) { while (x) { pushdown(x); if (siz[c[x][0]]+1==k) return x; if (siz[c[x][0]]+1>k) x=c[x][0]; else k-=siz[c[x][0]]+1,x=c[x][1]; } } inline int getpre(int x,int k) { int res; while (x) { pushdown(x); if (a[x]<=k) res=x,x=c[x][1]; else x=c[x][0]; } return res; } inline int getnxt(int x,int k) { int res; while (x) { pushdown(x); if (a[x]>k) res=x,x=c[x][0]; else x=c[x][1]; } return res; } inline void dfs(int x) { if (!x) return; pushdown(x); dfs(c[x][0]); s[++top]=x; dfs(c[x][1]); } inline void insert(int &x,int k,int last) { if (!x) {x=k;c[x][0]=c[x][1]=0;fa[x]=last;siz[x]=1;return;} pushdown(x); insert((a[x]>=a[k])?c[x][0]:c[x][1],k,x); pushup(x); } int main() { n=read(); q=read(); for (int i=2;i<=n+1;i++) a[i]=read(); sort(a+2,a+2+n); a[1]=-inf; a[n+2]=inf; build(rt,1,n+2,0); while (q--) { int op=read(),k=read(); if (op==1) { k=find(rt,k+1); splay(k,rt); write(a[k]); puts(""); } else { int x=getpre(rt,k),y=getnxt(rt,k<<1); splay(x,rt); splay(y,c[x][1]); int z=c[y][0]; if (z) top=0,dfs(z),fa[z]=c[y][0]=0; pushup(y); pushup(x); mark(y,-k); if (z) for (int i=1;i<=top;i++) a[s[i]]-=k,insert(rt,s[i],0),splay(s[i],rt); } } return 0; }
以上是关于[BZOJ4923]K小值查询的主要内容,如果未能解决你的问题,请参考以下文章
4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap