1. 程式人生 > 其它 >【演算法筆記】Hash

【演算法筆記】Hash

可持久化線段樹

如果我們要維護一個可持續的,支援查詢歷史版本的陣列該怎麼做

給每一個版本建立一顆線段樹?那太佔空間了。

我們可以不同版本公用一些節點,對於每個版本,只把和上一個版本不一樣的部分建立線段樹的新節點。這樣我們就有了可持久化線段樹。

Lisa

需要的前置知識:動態開點。

依照上面的思想,這個題只有單點修改和單點查詢,很容易解決。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
struct tree{
	int l;
	int r;
	int v;
}tr[24000006];
int cnt;
int f,x,y,z;
int n,m;
int a[10000001];
void build(int& ro,int l,int r){
	ro=++cnt;
	if(l==r){
		tr[ro].v=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(tr[ro].l,l,mid);
	build(tr[ro].r,mid+1,r);
}
int rt[1000001];
void update(int& ro,int pre,int l,int r,int po,int k){
	ro=++cnt;
	tr[ro]=tr[pre];
	if(l==r){
		tr[ro].v=k;
		return ;
	}
	int mid=(l+r)>>1;
	if(po<=mid) update(tr[ro].l,tr[pre].l,l,mid,po,k);
	else update(tr[ro].r,tr[pre].r,mid+1,r,po,k);
}
int que(int ro,int l,int r,int k){
	if(l==r){
		return tr[ro].v;
	}
	int mid=(l+r)>>1;
	if(k<=mid) return que(tr[ro].l,l,mid,k);
	else return que(tr[ro].r,mid+1,r,k);
}
int main(){
	read(n);read(m);
	for(int i=1;i<=n;++i){
		read(a[i]);
	}
	build(rt[0],1,n);
	for(int i=1;i<=m;++i){
		read(x);read(f);read(y);
		if(f==1){
			read(z);
			update(rt[i],rt[x],1,n,y,z);
		}else{
			printf("%d\n",que(rt[x],1,n,y));
			rt[i]=rt[x];
		}
	}
	return 0;
}

靜態區間第k小

建立一顆權值線段樹,按照上面的思想,每從左往右處理一個位置,就是建立一個新版本,如果要知道\([l,r]\),那麼只需要用這兩個端點對應的部分相減。就可以知道區間的資訊,然後線段樹上二分就可以了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
int n;
int m;
struct tree{
	int l;
	int r;
	int sum;
}tr[4800005];
int cnt;
void build(int &ro,int l,int r){
	ro=++cnt;
	tr[ro].sum=0;
	if(l==r){
		return ;
	}
	int mid=(l+r)>>1;
	build(tr[ro].l,l,mid);
	build(tr[ro].r,mid+1,r);
}
int a[1000005];
int b[1000005];
int l;
int rt[10000005];
void update(int &ro,int pre,int l,int r,int k){
	ro=++cnt;
	tr[ro]=tr[pre];
	tr[ro].sum=tr[pre].sum+1;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(k<=mid) update(tr[ro].l,tr[pre].l,l,mid,k);
	else update(tr[ro].r,tr[pre].r,mid+1,r,k);
}
int f;
int x;
int y;
int z;
int que(int pre,int rr,int l,int r,int k){
	if(l==r) return l;
	int mid=tr[tr[rr].l].sum-tr[tr[pre].l].sum;
	int mmid=(l+r)>>1;
	if(mid>=k){
		return que(tr[pre].l,tr[rr].l,l,mmid,k);
	}else{
		return que(tr[pre].r,tr[rr].r,mmid+1,r,k-mid);
	}
}
int main(){
	read(n);read(m);
	for(int i=1;i<=n;++i){
		read(a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	int ll=unique(b+1,b+n+1)-b-1;
	build(rt[0],1,ll);
	for(int i=1;i<=n;++i){
		int tem=lower_bound(b+1,b+ll+1,a[i])-b;
		update(rt[i],rt[i-1],1,ll,tem);
	}
	for(int i=1;i<=m;++i){
		read(x);read(y);read(z);
		printf("%d\n",b[que(rt[x-1],rt[y],1,ll,z)]);
	}
	return 0;
}