【演算法筆記】Hash
阿新 • • 發佈:2021-10-22
可持久化線段樹
如果我們要維護一個可持續的,支援查詢歷史版本的陣列該怎麼做
給每一個版本建立一顆線段樹?那太佔空間了。
我們可以不同版本公用一些節點,對於每個版本,只把和上一個版本不一樣的部分建立線段樹的新節點。這樣我們就有了可持久化線段樹。
需要的前置知識:動態開點。
依照上面的思想,這個題只有單點修改和單點查詢,很容易解決。
#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; }
建立一顆權值線段樹,按照上面的思想,每從左往右處理一個位置,就是建立一個新版本,如果要知道\([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; }