HDU - 4757 Tree(LCA+可持久化trie树)
題目鏈接:點(diǎn)擊查看
題目大意:給出一棵有有n個(gè)節(jié)點(diǎn)的樹,每個(gè)點(diǎn)都有一個(gè)權(quán)值,現(xiàn)在給出m個(gè)查詢,每次查詢的形式為:x,y,z,求出從點(diǎn)x到點(diǎn)y的路徑上任選一點(diǎn),使其與z的異或值最大,輸出異或值
題目分析:一開(kāi)始看到從一個(gè)區(qū)間內(nèi)任選一個(gè)點(diǎn)與指定的值異或取最值,立馬就想到了可持久化trie樹,可是這個(gè)題目是基于樹上操作的,我們?cè)撛趺磳渖系穆窂侥孟聛?lái)呢?其實(shí)這就涉及到了LCA,在給出兩個(gè)點(diǎn)x和y后,只需要求出兩個(gè)點(diǎn)的lca,就可以將x到y(tǒng)的路徑分為了x到lca的路徑+y到lca的路徑了,由于lca的深度肯定小于等于x和y中的任何一個(gè)值,所以我們就可以將x到y(tǒng)的路徑分為兩個(gè)區(qū)間了:[lca,x]和[lca,y],這樣就能使兩個(gè)算法配合操作了
關(guān)于在樹上建可持久化字典樹,我們只需要從根節(jié)點(diǎn)開(kāi)始遍歷,然后每次利用父節(jié)點(diǎn)的root繼承就可以了,因?yàn)槲覀冃枰膮^(qū)間是
[lca,x]和[lca,y],而可持久化的數(shù)據(jù)結(jié)構(gòu)可以當(dāng)做前綴和來(lái)理解,所以最后我們提供的點(diǎn)應(yīng)該是[fa[lca],x]和[fa[lca],y],fa數(shù)組代表的是當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn),這樣就能達(dá)到前綴和作差的形式了
通過(guò)這個(gè)題真的學(xué)到了很多,先是拋開(kāi)所需要的算法lca和可持久化字典樹不說(shuō),首先也是默寫代碼的一種能力,然后是調(diào)試的能力,因?yàn)橐婚_(kāi)始把lca函數(shù)中的deep[a]和deep[b]寫反了導(dǎo)致樣例都跑不出來(lái),還有就是對(duì)各個(gè)函數(shù)更加理解了,在調(diào)試的過(guò)程中,親手將一個(gè)遞歸程序換成了循環(huán)來(lái)寫,也是更進(jìn)一步的理解了可持久化字典樹這個(gè)數(shù)據(jù)結(jié)構(gòu)吧,也不枉我調(diào)了三個(gè)小時(shí),期間和zx學(xué)長(zhǎng)學(xué)到了好多比較先進(jìn)的知識(shí),首先在初始化時(shí)不需要用memset對(duì)trie和sum兩個(gè)比較大的數(shù)組直接初始化,我們可以定義一個(gè)newnode函數(shù),用來(lái)在使用之前初始化這兩個(gè)數(shù)組,還有就是在求lca時(shí),可以稍微暴力一點(diǎn),也暴力不到那里去,一開(kāi)始定義的范圍可以根據(jù)n來(lái)確定,下限是0毋庸置疑,上限我們可以設(shè)置為log2(n)+1,這樣的話可以保證對(duì)于較小程序的合理性
不多說(shuō)了,上代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;int n,m;int head[N];int a[N];//每個(gè)點(diǎn)的權(quán)值 int deep[N],fa[N];//每個(gè)點(diǎn)的深度和父節(jié)點(diǎn) int dp[N][20];//倍增 int trie[N*17][2];//字典樹 int sum[N*17];int root[N];int cnt,tot,k;struct edge {int to,next; }edge[N*2];void addedge(int u,int v) {edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;edge[tot].to=u;edge[tot].next=head[v];head[v]=tot++; }int LCA(int a,int b) {if(deep[a]<deep[b])swap(a,b);for(int i=k;i>=0;i--)if(deep[a]-deep[b]>=(1<<i))a=dp[a][i];if(a==b)return a;for(int i=k;i>=0;i--)if(dp[a][i]!=dp[b][i]){a=dp[a][i];b=dp[b][i];}return dp[a][0]; }int newnode() {cnt++;trie[cnt][0]=trie[cnt][1]=0;sum[cnt]=0;return cnt; }void insert(int pre,int &cur,int step,int x) {cur=newnode();trie[cur][0]=trie[pre][0];trie[cur][1]=trie[pre][1];sum[cur]=sum[pre]+1;if(step<0)return;int to=(x>>step)&1;insert(trie[pre][to],trie[cur][to],step-1,x); }int query(int l,int r,int step,int x) {if(step<0)return 0;int to=(x>>step)&1;if(sum[trie[r][!to]]-sum[trie[l][!to]]>0)return query(trie[l][!to],trie[r][!to],step-1,x)+(1<<step);elsereturn query(trie[l][to],trie[r][to],step-1,x); }void dfs(int u,int f,int dep) {insert(root[f],root[u],15,a[u]);deep[u]=dep;fa[u]=f;dp[u][0]=f;for(int i=1;i<=k;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(v==f)continue;dfs(v,u,dep+1);} }void init() {memset(head,-1,sizeof(head));cnt=0;tot=0;k=log2(n)+1; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF){init();for(int i=1;i<=n;i++)scanf("%d",a+i);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);addedge(u,v);}dfs(1,0,0);while(m--){int u,v,x;scanf("%d%d%d",&u,&v,&x);int lca=LCA(u,v);printf("%d\n",max(query(root[fa[lca]],root[u],15,x),query(root[fa[lca]],root[v],15,x)));}}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的HDU - 4757 Tree(LCA+可持久化trie树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: (转)LCA模板(倍增法)
- 下一篇: CodeForces - 566A Ma