标签:fine zjoi 区间查询 路径 mes print line ace --
主要思路如下:
外层为权值线段树,内层为动态开点线段树,也就是每个权值线段树上的节点开一个动态开点线段树。
外层的权值线段树支持查询排名,内层的线段树限制了区间。实际上就是在普通权值线段树上查询的价值变成了在其线段树上区间查询返回的值。
对于这道模板题,我们先写几个函数:
下方的update
为外层线段树,将路径上的所有点的线段树修改。
上方的update
为内层线段树,动态开点单点修改。
要判断k==1
为题目需要,因为如果是删除的话就不需要开点了。
变量解释:v
为权值,p
为下标,k
为修改的值。
void update(int &ro,int l,int r,int p,int k){
if(k==1 and !ro)ro=++tot;
if(ro) val[ro]+=k;
if(!ro or l==r)return;
int mid=l+r>>1;
(p<=mid)?update(ls[ro],l,mid,p,k):update(rs[ro],mid+1,r,p,k);
}
void update(int &ro,int l,int r,int v,int p,int k){
if(k==1 and !ro)ro=++Tot;
if(ro) update(rt[ro],1,n,p,k);
if(!ro or l==r)return;
int mid=l+r>>1;
(v<=mid)?update(Ls[ro],l,mid,v,p,k):update(Rs[ro],mid+1,r,v,p,k);
}
本题有多个查询:
注意判断边界情况。
int query(int ro,int l,int r,int x,int y){
if(!ro)return 0;
if(x<=l and y>=r)return val[ro];
int mid=l+r>>1;
return (x<=mid?query(ls[ro],l,mid,x,y):0)+(y>mid?query(rs[ro],mid+1,r,x,y):0);
}
int rank(int ro,int l,int r,int x,int y,int L,int R){
if(!ro)return 0;
if(x<=l and y>=r)return query(rt[ro],1,n,L,R);
int mid=l+r>>1;
return (x<=mid?rank(Ls[ro],l,mid,x,y,L,R):0)+(y>mid?rank(Rs[ro],mid+1,r,x,y,L,R):0);
}
int kth(int ro,int l,int r,int k,int L,int R){
if(l==r)return l;
int mid=l+r>>1,tmp=query(rt[Ls[ro]],1,n,L,R);
return (k<=tmp)?kth(Ls[ro],l,mid,k,L,R):kth(Rs[ro],mid+1,r,k-tmp,L,R);
}
inline int pre(int x,int y,int k){
int zp;
if(!(zp=rank(root,0,maxl,0,k-1,x,y)))return -2147483647;
return kth(root,0,maxl,zp,x,y);
}
inline int nxt(int x,int y,int k){
int zp;
if((zp=rank(root,0,maxl,0,k,x,y))==rank(root,0,maxl,0,maxl,x,y))return 2147483647;
return kth(root,0,maxl,zp+1,x,y);
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c==‘-‘,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=5e4+10,maxm=1e7+10,maxl=1e8;
int n,q,rt[maxm],ls[maxm*3],rs[maxm*3],Ls[maxm],Rs[maxm],val[maxm*3],tot,Tot,root;
int a[maxn];
void update(int &ro,int l,int r,int p,int k){
if(k==1 and !ro)ro=++tot;
if(ro) val[ro]+=k;
if(!ro or l==r)return;
int mid=l+r>>1;
(p<=mid)?update(ls[ro],l,mid,p,k):update(rs[ro],mid+1,r,p,k);
}
void update(int &ro,int l,int r,int v,int p,int k){
if(k==1 and !ro)ro=++Tot;
if(ro) update(rt[ro],1,n,p,k);
if(!ro or l==r)return;
int mid=l+r>>1;
(v<=mid)?update(Ls[ro],l,mid,v,p,k):update(Rs[ro],mid+1,r,v,p,k);
}
int query(int ro,int l,int r,int x,int y){
if(!ro)return 0;
if(x<=l and y>=r)return val[ro];
int mid=l+r>>1;
return (x<=mid?query(ls[ro],l,mid,x,y):0)+(y>mid?query(rs[ro],mid+1,r,x,y):0);
}
int rank(int ro,int l,int r,int x,int y,int L,int R){
if(!ro)return 0;
if(x<=l and y>=r)return query(rt[ro],1,n,L,R);
int mid=l+r>>1;
return (x<=mid?rank(Ls[ro],l,mid,x,y,L,R):0)+(y>mid?rank(Rs[ro],mid+1,r,x,y,L,R):0);
}
int kth(int ro,int l,int r,int k,int L,int R){
if(l==r)return l;
int mid=l+r>>1,tmp=query(rt[Ls[ro]],1,n,L,R);
return (k<=tmp)?kth(Ls[ro],l,mid,k,L,R):kth(Rs[ro],mid+1,r,k-tmp,L,R);
}
inline int pre(int x,int y,int k){
int zp;
if(!(zp=rank(root,0,maxl,0,k-1,x,y)))return -2147483647;
return kth(root,0,maxl,zp,x,y);
}
inline int nxt(int x,int y,int k){
int zp;
if((zp=rank(root,0,maxl,0,k,x,y))==rank(root,0,maxl,0,maxl,x,y))return 2147483647;
return kth(root,0,maxl,zp+1,x,y);
}
inline void work(){
n=read(),q=read();
for(int i=1;i<=n;i++) update(root,0,maxl,a[i]=read(),i,1);
while(q--){
int op=read(),x=read(),y=read();
switch(op){
case 1:printf("%d\n",rank(root,0,maxl,0,read()-1,x,y)+1);break;
case 2:printf("%d\n",kth(root,0,maxl,read(),x,y));break;
case 3:update(root,0,maxl,a[x],x,-1),update(root,0,maxl,a[x]=y,x,1);break;
case 4:printf("%d\n",pre(x,y,read()));break;
case 5:printf("%d\n",nxt(x,y,read()));break;
}
}
}
}
signed main(){
star::work();
return 0;
}
只剩一个询问查询k大数,区间修改。具体就是把上面内层的线段树变成了区间修改的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c==‘-‘,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=5e4+10,maxm=1e7+10,maxl=5e5+10;
int n,q,rt[maxm],ls[maxm*3],rs[maxm*3],Ls[maxm],Rs[maxm],val[maxm*3],tag[maxm*3],tot,Tot,root;
void pushdown(int ro,int l,int r){
int mid=floor((l+r)/2.0);
if(!tag[ro])return;
if(!ls[ro])ls[ro]=++tot;
if(!rs[ro])rs[ro]=++tot;
tag[ls[ro]]+=tag[ro],tag[rs[ro]]+=tag[ro];
val[ls[ro]]+=tag[ro]*(mid-l+1),val[rs[ro]]+=tag[ro]*(r-mid);
tag[ro]=0;
}
void pushup(int ro){
val[ro]=val[ls[ro]]+val[rs[ro]];
}
void update(int &ro,int l,int r,int x,int y,int k){
if(!ro)ro=++tot;
if(l==x and r==y)return (void)(tag[ro]+=k,val[ro]+=k*(r-l+1));
pushdown(ro,l,r);
int mid=floor((l+r)/2.0);
if(y<=mid) update(ls[ro],l,mid,x,y,k);
else if(x>mid) update(rs[ro],mid+1,r,x,y,k);
else update(ls[ro],l,mid,x,mid,k),update(rs[ro],mid+1,r,mid+1,y,k);
pushup(ro);
}
void update(int &ro,int l,int r,int v,int x,int y,int k){
if(!ro)ro=++Tot;
if(ro) update(rt[ro],1,n,x,y,k);
if(l==r)return;
int mid=floor((l+r)/2.0);
(v<=mid)?update(Ls[ro],l,mid,v,x,y,k):update(Rs[ro],mid+1,r,v,x,y,k);
}
int query(int ro,int l,int r,int x,int y){
if(!ro)return 0;
if(x==l and y==r)return val[ro];
pushdown(ro,l,r);
int mid=floor((l+r)/2.0);
if(y<=mid) return query(ls[ro],l,mid,x,y);
else if(x>mid) return query(rs[ro],mid+1,r,x,y);
else return query(ls[ro],l,mid,x,mid)+query(rs[ro],mid+1,r,mid+1,y);
}
int kth(int ro,int l,int r,int k,int L,int R){
if(l==r)return l;
int mid=floor((l+r)/2.0),tmp=query(rt[Rs[ro]],1,n,L,R);
return (k<=tmp)?kth(Rs[ro],mid+1,r,k,L,R):kth(Ls[ro],l,mid,k-tmp,L,R);
}
inline void work(){
n=read(),q=read();
while(q--){
int op=read(),l=read(),r=read(),x=read();
switch(op){
case 1:update(root,-maxl,maxl,x,l,r,1);break;
case 2:printf("%lld\n",kth(root,-maxl,maxl,x,l,r));break;
}
}
}
}
signed main(){
star::work();
return 0;
}
标签:fine zjoi 区间查询 路径 mes print line ace --
原文地址:https://www.cnblogs.com/BrotherHood/p/13901885.html