很久之前就学习过的算法,但是最近发现很多题目都可以用倍增的方法解决,并且十分好写,所以总结一下。
noip2013 货车运输
题目大意:n各点构成一个无向图,每条边有一个最大负载,有q辆货车,分别从不同的点到不同的点,求每辆货车最大运载量。
思路:为了满足最大负载,肯定是走图的最大生成树上的路径,并且答案就是每次路径上的最小边权。用倍增维护最小边权就可以了。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct use{ int xx,yy,va; }r[50001]; int next[100001]={0},point[10001]={0},en[100001]={0},fa[10001]={0},f[10001][15]={0}, g[10001][15]={0},dep[10001]={0},val[100001]={0}; int my_comp(const use &x,const use &y) { if (x.va>y.va) return 1; else return 0; } int rool(int x) { if (fa[x]!=x) fa[x]=rool(fa[x]); return fa[x]; } void dfs(int x,int i) { int j,y; dep[x]=i; for (j=1;j<=13;++j) { f[x][j]=f[f[x][j-1]][j-1]; g[x][j]=min(g[f[x][j-1]][j-1],g[x][j-1]); } y=point[x]; while (y!=0) { if (dep[en[y]]==0) { f[en[y]][0]=x; g[en[y]][0]=val[y]; dfs(en[y],i+1); } y=next[y]; } } int work(int x,int y) { int i,j,t,ans; if (dep[x]>dep[y]) { t=x;x=y;y=t; } ans=2100000000; for (i=13;i>=0;--i) { if (dep[x]<=dep[f[y][i]]) { ans=min(ans,g[y][i]); y=f[y][i]; } } if (x==y) return ans; for (i=13;i>=0;--i) if (f[x][i]!=f[y][i]) { ans=min(ans,min(g[x][i],g[y][i])); x=f[x][i];y=f[y][i]; } ans=min(ans,min(g[x][0],g[y][0])); return ans; } int main() { int r1,r2,n,m,q,i,j,x,y,tot=0; cin>>n>>m; for (i=1;i<=m;++i) scanf("%d%d%d",&r[i].xx,&r[i].yy,&r[i].va); sort(r+1,r+m+1,my_comp); for (i=1;i<=n;++i) { fa[i]=i; } for (i=1;i<=m;++i) { r1=rool(r[i].xx); r2=rool(r[i].yy); if (r1!=r2) { ++tot; next[tot]=point[r[i].xx]; point[r[i].xx]=tot; en[tot]=r[i].yy; val[tot]=r[i].va; ++tot; next[tot]=point[r[i].yy]; point[r[i].yy]=tot; en[tot]=r[i].xx; val[tot]=r[i].va; fa[r1]=r2; } } for (i=1;i<=n;++i) if (dep[i]==0) dfs(i,1); cin>>q; for (i=1;i<=q;++i) { scanf("%d%d",&x,&y); if (rool(x)!=rool(y)) printf("%d\n",-1); else printf("%d\n",work(x,y)); } }
水果姐逛水果街
题目大意:树上的一条路径,在使后面的权值减去前面的差最大。(变形1:可以修改权值;变形2:可以增加结点。)
思路:对于这种题目倍增或者链剖都可以解决。但是要十分注意信息(最大值、最小值、正着的最大差和反着的最大差)更新的顺序。(变形1:只能用链剖,可以很快的修改和查询;变形2:只能用倍增,因为倍增中,新加入一个点只需要用父亲的信息修改这个点的信息就可以了,不需要改动父亲,所以可以很快的求出。)
可是如果这两种变式结合在一起,该用什么呢?
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define maxnode 200005 #define inf 2100000000LL using namespace std; int fa[maxnode][20]={0},maxn[maxnode][20]={0},minn[maxnode][20]={0},zcha[maxnode][20]={0},tot=0, fcha[maxnode][20]={0},ai[maxnode]={0},point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0}, dep[maxnode]={0}; struct use{ int maxn,minn; }; void add(int u,int v) { ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v; ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void ins(int u,int faa) { int i; fa[u][0]=faa;dep[u]=dep[faa]+1;maxn[u][0]=max(ai[u],ai[faa]);minn[u][0]=min(ai[u],ai[faa]); zcha[u][0]=max(0,ai[faa]-ai[u]);fcha[u][0]=max(0,ai[u]-ai[faa]); for (i=1;i<=18;++i) { fa[u][i]=fa[fa[u][i-1]][i-1]; zcha[u][i]=max(zcha[u][i-1],max(zcha[fa[u][i-1]][i-1],maxn[fa[u][i-1]][i-1]-minn[u][i-1])); fcha[u][i]=max(fcha[u][i-1],max(fcha[fa[u][i-1]][i-1],maxn[u][i-1]-minn[fa[u][i-1]][i-1])); maxn[u][i]=max(maxn[u][i-1],maxn[fa[u][i-1]][i-1]); minn[u][i]=min(minn[u][i-1],minn[fa[u][i-1]][i-1]); } } void dfs(int u,int faa) { int i,j; ins(u,faa); for (i=point[u];i;i=next[i]) if ((j=en[i])!=faa) dfs(j,u); } int ask(int u,int v) { int i,j,ans=0; use ans1,ans2; ans1.maxn=ans1.minn=ai[u];ans2.maxn=ans2.minn=ai[v]; if (dep[u]>dep[v]) { for (i=18;i>=0;--i) if (dep[fa[u][i]]>=dep[v]) { ans=max(ans,max(zcha[u][i],maxn[u][i]-ans1.minn)); ans1.maxn=max(ans1.maxn,maxn[u][i]); ans1.minn=min(ans1.minn,minn[u][i]); u=fa[u][i]; } } else { for (i=18;i>=0;--i) if (dep[fa[v][i]]>=dep[u]) { ans=max(ans,max(fcha[v][i],ans2.maxn-minn[v][i])); ans2.maxn=max(ans2.maxn,maxn[v][i]); ans2.minn=min(ans2.minn,minn[v][i]); v=fa[v][i]; } } if (u==v) return ans; for (i=18;i>=0;--i) { if (fa[u][i]!=fa[v][i]) { ans=max(ans,max(zcha[u][i],max(maxn[u][i]-ans1.minn, max(fcha[v][i],ans2.maxn-minn[v][i])))); ans1.maxn=max(ans1.maxn,maxn[u][i]); ans1.minn=min(ans1.minn,minn[u][i]); ans2.maxn=max(ans2.maxn,maxn[v][i]); ans2.minn=min(ans2.minn,minn[v][i]); u=fa[u][i];v=fa[v][i]; } } ans=max(ans,max(zcha[u][0],maxn[u][0]-ans1.minn)); ans1.maxn=max(ans1.maxn,maxn[u][0]); ans1.minn=min(ans1.minn,minn[u][0]); ans=max(ans,max(fcha[v][0],ans2.maxn-ans1.minn)); return ans; } int main() { freopen("lct.in","r",stdin); freopen("lct.out","w",stdout); int n,m,i,j,q,ans=0,kk,u,v; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%d",&ai[i]); for (i=1;i<n;++i) { scanf("%d%d",&u,&v);add(u,v); } dfs(1,0);scanf("%d",&m); for (i=1;i<=m;++i) { scanf("%d%d%d",&kk,&u,&v); if (kk==1) { u^=ans;v^=ans;ans=ask(u,v);printf("%d\n",ans); } else { v^=ans;ai[++n]=u;ins(n,v); } } fclose(stdin); fclose(stdout); }