恩,这是一道神奇的LCA+难度的题目。
题目是这样的:
A 国有n座城市,编号从1到n,城市之间有 m条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
一开始看了看,以为是费用流(PS:一看就是费用流裸题嘛。。)
然后发现有Q个询问。。
完美TLE
然后zxyer狠狠D了我一顿(%%%)这才发现写LCA是正解。。(太像了woc)
好吧,说正解。
这道题出现了Q个询问,我们很快就会想到RMQ和LCA
可是这道题是个图,不一定是树。
根据最大生成树的性质(载重量最大的那条路径一定在最大生成树上)
RMQ处理区间最小值,而LCA有个性质,就是它一定在U到V的最短路上,而且是2个点到根节点的路径的第一个交点。所以到了LCA就没必要往上走了,
因为路径是公共的,结果不会比LCA更优;
然后RMQ处理最小值,再找一下LCA,输出载重量最小值
然后就AC啦
原来程序有BUG(好吧。终于DEBUG出来了。。)
注意!写CMP函数时,如果用>=号会爆栈!
下面贴程序~
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,num=0,q; struct edge{ int next,to,value; }g[100010]; int f[10010]; int depth[10010]; int visit[10010]; int fa[10010][20]; int r[50010]; int u[50010],v[50010],w[50010]; int dist [10010][20]; int head[10010]; int cmp(const int a,const int b) { return w[a]>w[b];} int getf(int x){ return x==f[x]?x:f[x]=getf(f[x]);} void addedge(int u,int v,int value){ g[++num].next=head[u]; head[u]=num; g[num].to=v; g[num].value=value; } void kruskal(){ for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) r[i]=i; sort(r+1,r+m+1,cmp); for(int i=1;i<=m;i++) { int x=u[r[i]]; int y=v[r[i]]; x=getf(x);y=getf(y); if(x!=y){ addedge(x,y,w[r[i]]); addedge(y,x,w[r[i]]); f[x]=y; } } } void prelca(int x){ visit[x]=1; for(int i=1;(1<<i)<=depth[x];i++) { int c=fa[x][i-1]; fa[x][i]=fa[c][i-1]; dist[x][i]=min(dist[x][i-1],dist[c][i-1]); } for(int i=head[x];i;i=g[i].next) { int v=g[i].to; if(!visit[v]) { depth[v]=depth[x]+1; fa[v][0]=x; dist[v][0]=g[i].value; prelca(v); } } } int lca(int x,int y) { int rr=2147483647; if(depth[x]<depth[y])swap(x,y); int dc=depth[x]-depth[y]; for(int i=0;(1<<i)<=dc;i++) if(((1<<i)&dc)&&fa[x][i]) { rr=min(rr,dist[x][i]); x=fa[x][i]; } if(x==y)return rr; for(int i=15;i>=0;i--) if(fa[x][i]!=fa[y][i]&&depth[x]>=(1<<i)&&fa[x][i]) { rr=min(rr,min(dist[x][i],dist[y][i])); x=fa[x][i]; y=fa[y][i]; } return min(rr,min(dist[x][0],dist[y][0])); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]); kruskal(); for(int i=1;i<=n;i++) if(!visit[i])prelca(i); scanf("%d",&q); for(int i=1;i<=q;i++) { int a,b; scanf("%d%d",&a,&b); if(getf(a)!=getf(b))printf("-1 "); else printf("%d ",lca(a,b)); } return 0; }
注意:RMQ别打超限,调用空指针会WA的