日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

可持久化(二)

發(fā)布時(shí)間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 可持久化(二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 【可持久化值域線(xiàn)段樹(shù)/主席樹(shù)】
    • 主席樹(shù)代碼
    • 【二維數(shù)點(diǎn)】
    • 例題

【可持久化值域線(xiàn)段樹(shù)/主席樹(shù)】

P3834 【模板】可持久化線(xiàn)段樹(shù) 1(主席樹(shù))
查詢(xún)序列區(qū)間第k小,靜態(tài)在線(xiàn)。給定 n 個(gè)整數(shù)構(gòu)成的序列,將對(duì)于指定的閉區(qū)間查詢(xún)其區(qū)間內(nèi)的第 k 小值。

類(lèi)似值域線(xiàn)段樹(shù)上二分求kth的方法,對(duì)于[l,r]區(qū)間內(nèi)部的 kth,若有[1,l-1]和[1,r]2個(gè)前綴所對(duì)應(yīng)的2棵值域線(xiàn)段樹(shù)rt0/rt1,也可以通過(guò):

比較 getSZ(rt1->ls) - getSZ(rt0->ls) 和 當(dāng)前k 的大小關(guān)系

來(lái)二分答案。

為了構(gòu)建所有前綴[1,i]對(duì)應(yīng)的動(dòng)態(tài)開(kāi)點(diǎn)值域線(xiàn)段樹(shù),用可持久化的方式依次將a[1…N]加入值域線(xiàn)段樹(shù),每次加入都生成一個(gè)新版本即可。空間O(NlogN),同時(shí)擁有 N棵 值域線(xiàn)段樹(shù)。注意這里主席樹(shù)支持在線(xiàn)詢(xún)問(wèn)但不支持修改。時(shí)間復(fù)雜度O(QlogN)。

主席樹(shù)代碼

#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<queue> #include<stack> #include<cmath> #include<set> #include<map> using namespace std; #define ll long longtypedef pair<int,int>P; const int INF=0x3f3f3f3f; const int N=200005; int a[N],b[N],tot=0; int rt[N],ls[N*20],rs[N*20],sum[N*20];void build(int &o,int l,int r){o=++tot;sum[o]=0;if(l==r)return ;int m=(l+r)>>1;build(ls[o],l,m);build(rs[o],m+1,r); }void update(int &o,int l,int r,int pre,int p){o=++tot;ls[o]=ls[pre];rs[o]=rs[pre];sum[o]=sum[pre]+1;if(l==r)return ;int m=(l+r)>>1;if(p<=m)update(ls[o],l,m,ls[pre],p);else update(rs[o],m+1,r,rs[pre],p); }int query(int lr,int rr,int l,int r,int k){if(l==r)return l;int m=(l+r)>>1;int cnt=sum[ls[rr]]-sum[ls[lr]];if(k<=cnt)return query(ls[lr],ls[rr],l,m,k);else return query(rs[lr],rs[rr],m+1,r,k-cnt); }int main(){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=a[i];}sort(a+1,a+1+n);int nn=unique(a+1,a+1+n)-(a+1);int l,r,k;build(rt[0],1,nn);for(int i=1;i<=n;i++){int x=lower_bound(a+1,a+1+nn,b[i])-a;update(rt[i],1,nn,rt[i-1],x);}while(m--){scanf("%d%d%d",&l,&r,&k);int ans=query(rt[l-1],rt[r],1,nn,k);printf("%d\n",a[ans]);} }

【二維數(shù)點(diǎn)】

這里的可持久化值域線(xiàn)段樹(shù)支持對(duì)一個(gè)下標(biāo)區(qū)間[l,r]中值域區(qū)間[vl,vr]內(nèi)的計(jì)數(shù)/求和等操作,相當(dāng)與靜態(tài)二維數(shù)點(diǎn),復(fù)雜度1個(gè)log。注意這里不支持動(dòng)態(tài)修改。
二維數(shù)點(diǎn)就是將(i,a[i])加入到主席樹(shù)中,比如查詢(xún)[l,r]中值域區(qū)間[vl,vr]中點(diǎn)的數(shù)量,在第r個(gè)樹(shù)中求[vl,vr]d的區(qū)間和(因?yàn)槭侵涤蚓€(xiàn)段樹(shù)),在第l-1個(gè)樹(shù)中求[vl,vr]的區(qū)間和,就用第r個(gè)樹(shù)(tr[r])減去樹(shù)(tr[l-1])

#include<bits/stdc++.h> #define LL long long #define INF (1<<20) #define MAXN 100005 #define getSZ(p) (p?p->sz:0) #define getLSZ(p) (p?getSZ(p->ls):0) #define getL(p) (p?p->ls:0) #define getR(p) (p?p->rs:0) using namespace std;struct Node{int l,r,sz;Node *ls, *rs;void update(){sz = getSZ(ls) + getSZ(rs);}} pool[50*MAXN], *rt[MAXN];int top = 0; int N,Q;Node* copyNode(Node* rt){Node *p = pool + (++top);*p = *rt;return p; }Node* newNode(int l, int r){Node *p = pool + (++top);p->l = l; p->r = r;return p; }Node* insert(Node* rt, int l, int r, int x){Node *p;if(rt) p = copyNode(rt);else p = newNode(l,r);++p->sz;if(p->l==x && p->r==x) return p;int mid = (l + r)/2;if(x<=mid) p->ls = insert(p->ls, l, mid, x);else p->rs = insert(p->rs, mid+1, r, x);p->update();return p; }int query(Node* pL, Node* pR, Node* p0, Node* p1, int k){if(pR && pR->l==pR->r) return pR->l;if(pL && pL->l==pL->r) return pL->l;int k1 = getLSZ(pL) + getLSZ(pR) - getLSZ(p0) - getLSZ(p1);if(k1 >= k) return query(getL(pL), getL(pR), getL(p0), getL(p1), k);else return query(getR(pL), getR(pR), getR(p0), getR(p1), k - k1); }int a[MAXN], c[MAXN]; vector<int> adj[MAXN]; bool vis[MAXN]; int anc[MAXN][21], dep[MAXN];void dfs(int u, int fa){vis[u] = 1;rt[u] = insert(rt[fa], 1, N, a[u]);for(int j=1;j<=20;j++){if(dep[u] <= (1<<j)) break;anc[u][j] = anc[anc[u][j-1]][j-1];}int v;for(int k=0;k<adj[u].size();k++){v = adj[u][k];if(vis[v]) continue;dep[v] = dep[u] + 1; anc[v][0] = u;dfs(v, u);} }int lca(int u, int v){if(dep[u] < dep[v]) swap(u,v);for(int j=20;j>=0;j--){if(dep[anc[u][j]] >= dep[v]){u = anc[u][j];}}if(u == v) return u;for(int j=20;j>=0;j--){if(anc[u][j] != anc[v][j]){u = anc[u][j];v = anc[v][j];}}return anc[u][0]; } int main(){scanf("%d%d", &N, &Q);for(int i=1;i<=N;i++) scanf("%d", &a[i]);memcpy(c,a,sizeof(a));sort(c+1,c+1+N);for(int i=1;i<=N;i++){a[i] = lower_bound(c+1,c+1+N,a[i]) - c;}int u,v;for(int i=1;i<N;i++){scanf("%d%d", &u, &v);adj[u].push_back(v);adj[v].push_back(u);}dep[1] = 1;dfs(1,0);int k, z, lastans = 0;while(Q--){scanf("%d%d%d", &u, &v, &k);u ^= lastans;z = lca(u, v);lastans = c[query(rt[u], rt[v], rt[z], rt[anc[z][0]], k)];printf("%d\n", lastans);}return 0; }

例題

P2633 Count on a tree
P3567 [POI2014]KUR-Couriers

總結(jié)

以上是生活随笔為你收集整理的可持久化(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。