树套树学习笔记

树套树

线段树套平衡树

思路
代码(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;
}
posted @ 2026-09-17 20:24  dgcsjfs  阅读(6)  评论(2)    收藏  举报