树套树学习笔记
树套树
线段树套平衡树
思路
代码(FHQ Treap)
#include <iostream>
#include <algorithm>
using namespace std;
const int N=30000005;
const int INF=2147483647;
int n,m,w[N],idx;
int l[N],r[N],val[N],rnd[N],siz[N];
inline void newnode(int &x,int v){
x=++idx;
val[x]=v;
rnd[x]=rand();
siz[x]=1;
}
inline void pushup(int x){
siz[x]=siz[l[x]]+siz[r[x]]+1;
}
inline void split(int p,int v,int &x,int &y){
if(!p){x=y=0; return;}
if(val[p]<=v)
x=p, split(r[p],v,r[p],y);
else
y=p, split(l[p],v,x,l[p]);
pushup(p);
}
inline int merge(int x,int y){
if(!x || !y) return x+y;
if(rnd[x] < rnd[y]){
r[x]=merge(r[x],y);
pushup(x); return x;
}
else{
l[y]=merge(x,l[y]);
pushup(y); return y;
}
}
inline void insert(int &root,int v){
int x,y,z;
split(root,v,x,y);
newnode(z,v);
root=merge(merge(x,z),y);
}
inline void del(int &root,int v){
int x,y,z;
split(root,v,x,z);
split(x,v-1,x,y);
y=merge(l[y],r[y]);
root=merge(x,merge(y,z));
}
inline int getrank(int &root,int v){
int x,y,z,ans;
split(root,v-1,x,y);
ans=siz[x]+1;
root=merge(x,y);
return ans;
}
inline int getval(int x,int k){
if(k==siz[l[x]]+1) return val[x];
if(k<=siz[l[x]]) return getval(l[x],k);
return getval(r[x],k-siz[l[x]]-1);
}
inline int getpre(int &root,int v){
int x,y,z,ans;
split(root,v-1,x,y);
ans = siz[x]?getval(x,siz[x]):-INF;
root = merge(x,y);
return ans;
}
inline int getnxt(int &root,int v){
int x,y,z,ans;
split(root,v,x,y);
ans = siz[y]?getval(y,1):INF;
root = merge(x,y);
return ans;
}
#define lc (u<<1)
#define rc (u<<1|1)
int root[N];
void build(int u,int l,int r){
for(int i=l;i<=r;i++) insert(root[u],w[i]);
if(l==r) return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
int queryrank(int u,int l,int r,int x,int y,int v){
if(x<=l && r<=y) return getrank(root[u],v)-1;
int mid=l+r>>1,res=0;
if(x<=mid) res += queryrank(lc,l,mid,x,y,v);
if(y>mid) res += queryrank(rc,mid+1,r,x,y,v);
return res;
}
int queryval(int u,int x,int y,int v){
int l=0,r=1e8,ans;
while(l<=r){
int mid=l+r>>1;
if(queryrank(1,1,n,x,y,mid)+1<=v)
ans=mid, l=mid+1;
else r=mid-1;
}
return ans;
}
void change(int u,int l,int r,int p,int v){
del(root[u],w[p]);
insert(root[u],v);
if(l==r) return;
int mid=l+r>>1;
if(p<=mid) change(lc,l,mid,p,v);
else change(rc,mid+1,r,p,v);
}
int querypre(int u,int l,int r,int x,int y,int v){
if(x<=l && r<=y) return getpre(root[u],v);
int mid=l+r>>1,res=-INF;
if(x<=mid) res=max(res,querypre(lc,l,mid,x,y,v));
if(y>mid) res=max(res,querypre(rc,mid+1,r,x,y,v));
return res;
}
int querynxt(int u,int l,int r,int x,int y,int v){
if(x<=l && r<=y) return getnxt(root[u],v);
int mid=l+r>>1,res=INF;
if(x<=mid) res=min(res,querynxt(lc,l,mid,x,y,v));
if(y>mid) res=min(res,querynxt(rc,mid+1,r,x,y,v));
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
while(m -- ){
int op,x,y,v;
scanf("%d",&op);
if(op==3)scanf("%d%d",&x,&v);
else scanf("%d%d%d",&x,&y,&v);
if(op==1)
printf("%d\n",queryrank(1,1,n,x,y,v)+1);
if(op==2)
printf("%d\n",queryval(1,x,y,v));
if(op==3)
change(1,1,n,x,v), w[x]=v;
if(op==4)
printf("%d\n",querypre(1,1,n,x,y,v));
if(op==5)
printf("%d\n",querynxt(1,1,n,x,y,v));
}
return 0;
}
数点point
本题也可以用 cdq分治 解决
解题思路
把這個限制放到坐標軸上,發現其實就是求一個橫著的正方形區域裏面的最大曼哈頓距離,可以將 $x$ 坐標令成 $x+y$ . $y$ 坐標令成 $x-y$ 轉化為切比雪夫距離,就成了一個于坐標軸平行的矩形區域裏面的最大值,可以使用綫段樹套綫段樹維護,外層 $x$ 坐標内層 $y$ 坐標結合成點.時間複雜度 $\mathcal{O(n \log^2 n)}$.可以通過 $n\le 6 \times 10^5$ 的數據代码(樹套樹)
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5,M=2e5+5;
int n,q,a[N];
struct segtr2{
int cnt=0,ls=0,rs=0;
}otr[N*40],tr[N*40];
int tot=0,tot1=0,idx[N*40];
#define lc (u<<1)
#define rc (u<<1|1)
void New(int &u){
u=++tot1;
}
void add1(int &u,int l,int r,int y){
if(!u) New(u);
otr[u].cnt++;
if(l==r)return ;
int mid=(l+r)>>1;
if(y<=mid)add1(otr[u].ls,l,mid,y);
else add1(otr[u].rs,mid+1,r,y);
}
void add(int u,int l,int r,int x,int y){
add1(idx[u],-M,M,y);
if(l==r)return ;
int mid=(l+r)>>1;
if(x<=mid)add(lc,l,mid,x,y);
else add(rc,mid+1,r,x,y);
}
int query1(int u,int l,int r,int ql,int qr){
if(!u||r<ql||l>qr)return 0;
if(l>=ql&&r<=qr)return otr[u].cnt;
int mid=(l+r)>>1;
return query1(otr[u].ls,l,mid,ql,qr)+query1(otr[u].rs,mid+1,r,ql,qr);
}
int query(int u,int l,int r,int ql,int qr,int _ql,int _qr){
if(qr<l||ql>r)return 0;
if(ql<=l&&qr>=r)return query1(idx[u],-M,M,_ql,_qr);
int mid=(l+r)>>1;
return query(lc,l,mid,ql,qr,_ql,_qr)+query(rc,mid+1,r,ql,qr,_ql,_qr);
}
int main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
int u=a[i]+i,v=i-a[i];
add(1,1,M,u,v);
}
while(q--){
string op;int x,k;
cin>>op>>x>>k;
if(op=="Modify"){
a[x]=k;
add(1,1,M,a[x]+x,x-a[x]);
}
else{
int u=a[x]+x,v=x-a[x];
cout<<query(1,1,M,max(1,u-k),min(M,u+k),max(-M,v-k),min(M,v+k))<<"\n";
}
}
return 0;
}

浙公网安备 33010602011771号