HIT暑期集訓Day17 lca與rmq
阿新 • • 發佈:2020-08-21
rmq,求區間最大最小值模板,以POJ - 3264為例
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define maxn 50005 using namespace std; int a[maxn],dp[maxn][30][2]; void ST(int n) { int i,j; for (i=1;i<=n;i++) dp[i][0][0]=dp[i][0][1]=a[i]; for (j=1;(1<<j)<=n;j++) {rmq模板for (i=1;i+(1<<j)-1<=n;i++) { dp[i][j][0]=max(dp[i][j-1][0],dp[i+(1<<(j-1))][j-1][0]); dp[i][j][1]=min(dp[i][j-1][1],dp[i+(1<<(j-1))][j-1][1]); } } } int getk(int l,int r) { int k=0; while ((1<<(k+1))<=r-l+1) k++; returnk; } int rmq_max(int l,int r,int k) { return max(dp[l][k][0],dp[r-(1<<k)+1][k][0]); } int rmq_min(int l,int r,int k) { return min(dp[l][k][1],dp[r-(1<<k)+1][k][1]); } int main() { int i,x,y,k,n,q,ans; scanf("%d%d",&n,&q); for (i=1;i<=n;i++) scanf("%d",&a[i]); ST(n);while (q--) { scanf("%d%d",&x,&y); k=getk(x,y); ans=rmq_max(x,y,k)-rmq_min(x,y,k); printf("%d\n",ans); } return 0; }
樹鏈剖分求lca模板,以POJ - 1330為例
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define maxn 10005 using namespace std; struct edge { int to,nxt; }e[maxn]; int num,last[maxn],deg[maxn]; int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn]; void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void dfs1(int u,int father,int depth) { int i,v; fa[u]=father; dep[u]=depth; siz[u]=1; for (i=last[u];i;i=e[i].nxt) { v=e[i].to; if (v==father) continue; dfs1(v,u,depth+1); siz[u]+=siz[v]; if (siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; if (!son[u]) return; dfs2(son[u],tp); int i,v; for (i=last[u];i;i=e[i].nxt) { v=e[i].to; if (v!=son[u] && v!=fa[u]) dfs2(v,v); } } int query(int x,int y) { int tx=top[x],ty=top[y]; while (tx!=ty) { if (dep[tx]>=dep[ty]) x=fa[tx],tx=top[x]; else y=fa[ty],ty=top[y]; } if (dep[x]>dep[y]) return y; return x; } int main() { int T,i,x,y,n,rt; scanf("%d",&T); while (T--) { num=0; memset(last,0,sizeof(last)); memset(son,0,sizeof(son)); memset(deg,0,sizeof(deg)); scanf("%d",&n); for (i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y);deg[y]++; } for (i=1;i<=n;i++) if (deg[i]==0) { rt=i;break; } dfs1(rt,0,0); dfs2(rt,0); scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); } return 0; }樹鏈剖分求lca
題意:給一棵樹,每次詢問給三個點,這三個點可以隨意排列,分別為s,f,t,問s到f的路徑上與t到f的路徑上有幾個兩路徑共有的節點。
可以發現答案為(dis[s->f]+dis[t->f]-dis[s->t])/2+1(由於是求共有節點所以要+1),而dis[x->y]=dep[x]+dep[y]-2*dep[lca(x,y)],用樹鏈剖分就可求出dep與lca,從而求出dis。
對於每次詢問,列舉三種f的情況,其中的最大值就是答案。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define maxn 100005 using namespace std; struct edge { int to,nxt; }e[maxn<<1]; int num,last[maxn]; int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn]; void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void dfs1(int u,int father,int depth) { int i,v; fa[u]=father; dep[u]=depth; siz[u]=1; for (i=last[u];i;i=e[i].nxt) { v=e[i].to; if (v==father) continue; dfs1(v,u,depth+1); siz[u]+=siz[v]; if (siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; if (!son[u]) return; dfs2(son[u],tp); int i,v; for (i=last[u];i;i=e[i].nxt) { v=e[i].to; if (v!=son[u] && v!=fa[u]) dfs2(v,v); } } int lca(int x,int y) { int tx=top[x],ty=top[y]; while (tx!=ty) { if (dep[tx]>=dep[ty]) x=fa[tx],tx=top[x]; else y=fa[ty],ty=top[y]; } if (dep[x]>dep[y]) return y; return x; } int getdis(int x,int y) { int xy=lca(x,y); return dep[x]+dep[y]-2*dep[xy]; } int getans(int s,int f,int t) { return (getdis(s,f)+getdis(f,t)-getdis(s,t))/2; } int main() { int T,i,x,y,z,n,q,ans; while (scanf("%d%d",&n,&q)!=EOF) { num=0; memset(last,0,sizeof(last)); memset(son,0,sizeof(son)); for (i=2;i<=n;i++) { scanf("%d",&x); add(x,i);add(i,x); } dfs1(1,0,0); dfs2(1,0); while (q--) { scanf("%d%d%d",&x,&y,&z); ans=getans(x,y,z); ans=max(ans,getans(y,x,z)); ans=max(ans,getans(x,z,y)); printf("%d\n",ans+1); } } return 0; }View Code
G HDU 5023
J POJ 2019