树上倍增
来源:互联网 发布:快餐餐饮软件 编辑:程序博客网 时间:2024/05/02 23:40
寒假集训第一天和最后一天分别考了这两道题,这两道题做法几乎完全一样,可谓首尾呼应,然而我还是没做对(捂脸),果然还是编程能力有问题。
两道题做法均为先Kruskal求最大或最小生成树,之后被增求LCA,同时记录最值。
个人认为难点有二:
- 初始化时要同时记录一个跟anc结构相似的数组记录最值,以便倍增往上跳时快速求出最值
处理森林,需要对每棵BSTdfs初始化
注:当时看到题目上写不保证没有重边和自环还担心要不要特判一下,其实Kruskal完全可以处理带有重边和自环的图
下面是Nav的代码,Truck的话就是把impossible改成-1、cmp改个符号、求最小值即可
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)using namespace std;const int MAXN=1e5,MAXM=3e5;void swap(int & a,int & b){int t=a;a=b;b=t;}struct node{int u,v,w;} a[MAXM+1];int acnt;bool cmp(const node & a,const node & b){return a.w<b.w;}int head[MAXN+1],ecnt;struct edge{int next,to,value;} e[MAXM+1];void add(int x,int y,int z){ecnt++,e[ecnt].to=y,e[ecnt].next=head[x],head[x]=ecnt,e[ecnt].value=z;}int fa[MAXN+1];int getfa(int x){ if(fa[x]==x) return x; return fa[x]=getfa(fa[x]);}void unionset(int x,int y){fa[getfa(x)]=getfa(y);}int N,M,Q;int anc[MAXN+1][32];int deep[MAXN+1];int maxv[MAXN+1][32];void dfs(int now,int from){ for(int tmp=head[now];tmp;tmp=e[tmp].next) { if(e[tmp].to==from) continue; deep[e[tmp].to]=deep[now]+1; anc[e[tmp].to][0]=now; maxv[e[tmp].to][0]=e[tmp].value; dfs(e[tmp].to,now); }}void ready(){ int i,j; for(i=1;(1<<i)<=N;i++) for(j=1;j<=N;j++) { anc[j][i]=anc[anc[j][i-1]][i-1]; maxv[j][i]=max(maxv[j][i-1],maxv[anc[j][i-1]][i-1]); }}int ans;int getlca(int x,int y){ if(deep[x]<deep[y]) swap(x,y); int maxlogn=floor(log(N)/log(2)); int i,j; for(i=maxlogn;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) ans=max(ans,maxv[x][i]),x=anc[x][i]; if(x==y) return x; for(i=maxlogn;i>=0;i--) if(anc[x][i]!=anc[y][i]) { ans=max(ans,max(maxv[x][i],maxv[y][i])); x=anc[x][i];y=anc[y][i]; } ans=max(ans,maxv[x][0]);ans=max(ans,maxv[y][0]); return anc[x][0];}int main(){ freopen("nav.in","r",stdin); freopen("nav.out","w",stdout); int i; cin>>N>>M; for(i=1;i<=M;i++) { acnt++; scanf("%d%d%d",&a[acnt].u,&a[acnt].v,&a[acnt].w); } sort(a+1,a+M+1,cmp); int tot=0; for(i=1;i<=N;i++) fa[i]=i; for(i=1;i<=M;i++) { if(getfa(a[i].u)!=getfa(a[i].v)) { unionset(a[i].u,a[i].v); tot++; add(a[i].u,a[i].v,a[i].w); add(a[i].v,a[i].u,a[i].w); }if(tot>=N-1) break; } for(i=1;i<=N;i++)//对森林中每棵MST进行dfs预处理 if(!anc[i][0]) dfs(getfa(i),getfa(i)); ready(); cin>>Q; for(i=1;i<=Q;i++) { int A,B; scanf("%d%d",&A,&B); if(getfa(A)!=getfa(B))//判断A、B两点是否在同一MST中 { printf("impossible\n"); continue; } ans=0; getlca(A,B); printf("%d\n",ans); } return 0;}
所以说我是跟树上倍增有仇吗,今天又考了一道,树上倍增优化动规,然而我把状态转移方程写错了……
状态转移方程:
边界条件:
代码
#include<iostream>#include<cstdio>#define min(a,b) (a<b?a:b)#define max(a,b) (a>b?a:b)using namespace std;typedef long long ll;const int MAXN=1e5,MAXM=1e5,MAXQ=1e5,INF=~0U>>1;int n,m,q;struct E{int to,next;} e[MAXM+1];int ecnt,G[MAXN+1];void addEdge(int u,int v){e[++ecnt]=(E){v,G[u]};G[u]=ecnt;}struct T{int next,k,w;} tic[MAXN+1];int tcnt,tH[MAXN+1];void addTic(int v,int k,int w){tic[++tcnt]=(T){tH[v],k,w};tH[v]=tcnt;}int anc[MAXN+1][18],tmin[MAXN+1][18];int f[MAXN+1];void dfs(int u,int fa){ int i; anc[u][0]=fa,tmin[u][0]=f[fa]; for(i=1;i<=18;i++) { anc[u][i]=anc[anc[u][i-1]][i-1]; tmin[u][i]=min(tmin[u][i-1],tmin[anc[u][i-1]][i-1]); } f[u]=u==1?0:INF; for(i=tH[u];i;i=tic[i].next) { ll tmp=INF,v=u,k=tic[i].k,p=0; while(k) { if(k&1) { tmp=min(tmp,tmin[v][p]); v=anc[v][p]; }p++,k>>=1; } f[u]=min(f[u],tmp+tic[i].w); } for(i=G[u];i;i=e[i].next) dfs(e[i].to,u);}int main(){ freopen("party.in","r",stdin); freopen("party.out","w",stdout); int i; scanf("%d%d",&n,&m); for(i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); addEdge(v,u); } for(i=1;i<=m;i++) { int v,k,w; scanf("%d%d%d",&v,&k,&w); addTic(v,k,w); } dfs(1,1); scanf("%d",&q); while(q--) { int pos; scanf("%d",&pos); printf("%d\n",f[pos]); } return 0;}
0 0
- 树上倍增
- 【树上倍增算法模板】
- cf588e & bzoj3306 树上倍增
- noip2013truck树上路径倍增
- 3306: 树 树上倍增
- 树上倍增实现lca
- 树上倍增求LCA
- *树上倍增(LCA)
- 【复习记录】树上倍增
- 【bzoj2953】【poi2002】【商务旅行】【树上倍增】
- 关于树上倍增求LCA
- 【运输计划】【二分】【树上倍增】
- Codeforces 587C【树上倍增】
- 树上倍增法求LCA
- 树上倍增解析(转载)
- zoj 3649 树上的倍增法
- NOIP 2013 货车运输(树上倍增)
- BZOJ 4082 Wf2014 Surveillance 树上倍增
- 一段可以让整个网站变黑白代码
- ThinkPHP之数据删除和执行原生SQL语句
- SQLite数据库错误:The database disk image is malformed 解决(修复)方法
- 二叉树期权定价模型
- Spring IOC和AOP 原理
- 树上倍增
- 搜集的一些多平台博客编辑器,轻松一次编辑多平台发布
- pychram连接sourcetree
- 表情键盘 文字键盘 切换(保证了表情键盘也有键盘通知)
- 【Inno Setup】修改欢迎界面文字与安装向导文字颜色
- iOS 之 列表联动
- java awt实现小程序动态闪图源代码例子下载:I Iove You
- android之线程池
- 自适应中心点个数的K-means java实现