1. 程式人生 > 其它 >[Zjoi2013]K大數查詢——樹套樹

[Zjoi2013]K大數查詢——樹套樹

技術標籤:資訊競賽解題資料結構樹套樹

題目

[Zjoi2013]K大數查詢

題解

題意大概是給你n個vector,對若干個編號連續的vector進行插入和查詢。

典型的樹套樹唄

先對所有插入的c值建一棵線段樹,然後每個節點再維護一棵線段樹,葉子節點的線段樹存該值在序列中的分佈情況(也就是該值在序列中每個vector中的出現次數,維護區間和),父節點的線段樹存限定區間內的所有c值在序列中的分佈情況,也就是所有子節點的線段樹合併。

插入就是對大線段樹單點修改,對鏈上每個小線段樹進行區間加;

查詢就是利用大線段樹進行二分答案,每次對小線段樹進行區間查詢,總複雜度O(n\log^2n)

樹套樹的碼量名不虛傳,好在我板子打得優美,少除錯。

程式碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#define ll long long
#define MAXN 50005
#define MAXP 20000005
using namespace std;
inline ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
	return f?x:-x;
}
int n;

struct itn{    //小線段樹
	int ls,rs,lz;ll a;
	itn(){ls=rs=lz=a=0;}
}t[MAXP];
int IN;
inline void pushd(int x,int l,int r){
	if(t[x].lz>0){
		if(l==r){t[x].lz=0;return;}
		int mid=(l+r)>>1;
		if(!t[x].ls)t[x].ls=++IN,t[IN]=itn();
		t[t[x].ls].a+=(1ll+mid-l)*t[x].lz,t[t[x].ls].lz+=t[x].lz;
		if(!t[x].rs)t[x].rs=++IN,t[IN]=itn();
		t[t[x].rs].a+=(0ll+r-mid)*t[x].lz,t[t[x].rs].lz+=t[x].lz;
		t[x].lz=0;
	}
}
inline void addt(int x,int l,int r,int a,int b){
	if(l==a&&r==b){
		t[x].a+=r-l+1,t[x].lz++;
		return;
	}
	int mid=(l+r)>>1;pushd(x,l,r);
	if(a<=mid){
		if(!t[x].ls)t[x].ls=++IN,t[IN]=itn();
		addt(t[x].ls,l,mid,a,min(b,mid));
	}
	if(b>mid){
		if(!t[x].rs)t[x].rs=++IN,t[IN]=itn();
		addt(t[x].rs,mid+1,r,max(a,mid+1),b);
	}
	t[x].a=t[t[x].ls].a+t[t[x].rs].a;
}
inline ll sch(int x,int l,int r,int a,int b){
	if(!x)return 0;
	if(l==a&&r==b)return t[x].a;
	int mid=(l+r)>>1;pushd(x,l,r);
	ll res=0;
	if(a<=mid)res+=sch(t[x].ls,l,mid,a,min(b,mid));
	if(b>mid)res+=sch(t[x].rs,mid+1,r,max(a,mid+1),b);
	return res;
}

struct ITN{    //大線段樹
	int ls,rs,id;
}tr[MAXN<<4];
int NN;
inline void add(int x,int l,int r,int a,int b,int z){
	if(l==r){addt(tr[x].id,1,n,a,b);return;}
	int mid=(l+r)>>1;
	if(z<=mid){
		if(!tr[x].ls)tr[x].ls=++NN,tr[tr[x].ls].id=++IN,t[IN]=itn();
		add(tr[x].ls,l,mid,a,b,z);
	}
	else{
		if(!tr[x].rs)tr[x].rs=++NN,tr[tr[x].rs].id=++IN,t[IN]=itn();
		add(tr[x].rs,mid+1,r,a,b,z);
	}
	addt(tr[x].id,1,n,a,b);
}
inline int query(int x,int l,int r,int a,int b,ll c){
	if(l==r)return l;
	int mid=(l+r)>>1;ll z=sch(tr[tr[x].rs].id,1,n,a,b);
	if(z>=c)return query(tr[x].rs,mid+1,r,a,b,c);
	else return query(tr[x].ls,l,mid,a,b,c-z);
}

signed main()
{
	n=read();
	tr[++NN].id=++IN;
	for(int M=read();M--;){
		int opt=read(),a=read(),b=read();ll c=read();
		if(opt==1)add(1,-n,n,a,b,c);
		else printf("%d\n",query(1,-n,n,a,b,c));
	}
	return 0;
}