利用fhqTreap解决区间序列问题
利用fhq treap 解决了一道区间序列的问题.
题目是2020hdu多校第9场的一个题目.
题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=6873
代码留存
// 33897476 2020-09-09 23:28:50 Accepted 6873 3556MS 8516K 3787B G++ mainland
#include <bits/stdc++.h>
using namespace std;
#define inc(i,a,b) for(int i=a;i<=b;i++)
#define dec(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mst(a,b) memset(a,b,sizeof a)
#define pb push_back
inline int read(){
char ch=getchar();int f=1,x=0;
while(!isdigit(ch)) { if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return f*x;
}
//by Sshwy
int n,q;
const int SZ = 5e5+5;
// fhq treap 的模板
template<class T>
struct Treap{
int root,tot;
int mem[SZ],memp;
int lc[SZ],rc[SZ],sz[SZ];
unsigned int rnd[SZ];
T val[SZ],mn[SZ];
long long s[SZ];
void clear(){
fill(lc,lc+tot+1,0);
fill(rc,rc+tot+1,0);
fill(sz,sz+tot+1,0);
root=tot=0;
}
Treap(){
root=tot=0;
srand(clock()+time(0));
s[0] = val[0] = 0;
mn[0]=1e9;
}
inline void pushup(int u){
sz[u] = sz[lc[u]]+sz[rc[u]]+1;
mn[u] = min(val[u],min(mn[lc[u]],mn[rc[u]]));
s[u]=s[lc[u]]+s[rc[u]]+val[u];
}
void split(int u,const int left_size,int &x,int &y){
if(!u)return x=y=0,void();
if(sz[lc[u]]+1<=left_size)x=u,split(rc[u],left_size-sz[lc[u]]-1,rc[u],y);
else y=u,split(lc[u],left_size,x,lc[u]);
pushup(u);
}
//按住权值拆分为两颗子树
void split_by_val(int now,const T k,int &x,int &y){
if(!now) return x=y=0,void();
if(val[now]<=k) x=now,split_by_val(rc[now],k,rc[now],y);
else y=now,split_by_val(lc[now],k,x,lc[now]);
pushup(now);
}
//按照排名拆分成两颗子树
//和split其实是一样的 k = left_size
void split_by_rank(int now,int k,int &x,int &y){
if(!now) return x=y=0,void();
if(sz[lc[now]]+1<=k) x=now,split_by_rank(rc[now],k-sz[lc[now]]-1,rc[now],y);
else y=now,split_by_rank(lc[now],k,x,lc[now]);
pushup(now);
}
//x,y两个子树,且所有的节点的值都小于y的所有节点的值
//随机权重以小根堆的形式存储
int merge(int x,int y){//x<y
if(!x||!y)return x+y;
//if(rand()%(sz[x]+sz[y])<sz[x])return rc[x]=merge(rc[x],y), pushup(x), x;
if(rnd[x]<rnd[y])return rc[x]=merge(rc[x],y), pushup(x), x;
else return lc[y]=merge(x,lc[y]), pushup(y), y;
}
//虽然可能不满足堆的性质,但是,堆在这个过程中只是调节树的平衡的,所以还是可以过的
int dfs(int * a, int l,int r){
if(l>r) return 0;
int u=++tot,mid=l+r>>1;
s[u]=val[u]=mn[u]=a[mid],sz[u]=r-l+1,rnd[u]=rand();
lc[u]=dfs(a,l,mid-1);
rc[u]=dfs(a,mid+1,r);
pushup(u);
return u;
}
void build_from(int *a,int l,int r){
root=dfs(a,l,r);
}
void dfs_seq(int u,T *p){
if(u==0) return;
dfs_seq(lc[u],p);
*(p+sz[lc[u]]+1) = val[u];
dfs_seq(rc[u],p+sz[lc[u]]+1);
}
void seq(T *p){
dfs_seq(root,p);
}
T kth(int k){
int u=root;
while(k!=sz[lc[u]]+1){
if(k<=sz[lc[u]]) u=lc[u];
else k-=sz[lc[u]]+1,u=rc[u];
}
return val[u];
}
void split_by_min(int now,const int right_mn,int &x,int &y){
if(!now) return x=y=0,void();
if(mn[rc[now]]<right_mn || val[now]< right_mn)
x=now,split_by_min(rc[now],right_mn,rc[now],y);
else y=now,split_by_min(lc[now],right_mn,x,lc[now]);
pushup(now);
}
long long perform(int x,int y){
if(kth(x)<y) return 0;
int L,R;
split_by_rank(root,x,L,R);
if(mn[L]>=y) {
root=merge(L,R);
return 0;
}
int l,r;
split_by_min(L,y,l,r);
int l1,l2,r1,r2;
ll res=s[r]-sz[r]*1LL*(y-1);
split(l,sz[l]-1,l1,l2);
split(r,1,r1,r2);
val[l2]+=val[r1]-(y-1);
s[l2]=mn[l2]=val[l2];
s[r1]=mn[r1]=val[r1]=y-1;
root=merge(merge(merge(l1,l2),merge(r2,r1)),R);
return res;
}
};
Treap<int> T;
const int N=2e5+5;
int b[N];
void go(){
scanf("%d%d",&n,&q);
T.clear();
inc(i,1,n) scanf("%d",b+i);
T.build_from(b,1,n);
inc(i,1,q){
int op,x,y;
scanf("%d%d",&op,&x);
if(op==1) scanf("%d",&y),printf("%lld\n",T.perform(x,y));
else printf("%d\n",T.kth(x));
}
T.seq(b);
inc(i,1,n) printf("%d%c",b[i]," \n"[i==n]);
}
int main(){ int t=read();while(t--) go();return 0; }
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!