bnuoj 24258 Journey(lca倍增法 弱校聯萌十一大決戰之背水一戰J)
阿新 • • 發佈:2019-02-09
題意:在一棵n個節點的樹上,每條邊有權值,x->y的路徑長度為路徑上權值相加。現在在樹上新增一條u->v的邊,問q個詢問兩點間的最短路徑長度是否減少,減少了多少。
思路:新增邊之前,任意兩點間的路徑長度可通過倍增法求LCA在logn的時間求出,現在加了一條新邊用同樣的方法強行通過新邊進行比較即可。
<span style="font-size:14px;">//#pragma comment(linker, "/STACK:10240000000,10240000000") #include<iostream> #include<stdio.h> #include<math.h> #include <string> #include<string.h> #include<map> #include<queue> #include<set> #include<utility> #include<vector> #include<algorithm> #include<stdlib.h> using namespace std; #define eps 1e-8 #define pii pair<int,int> #define inf 0x3f3f3f3f #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define ll long long int #define mod 1000000007 #define maxn 100100 #define maxm 1000005 const int deg=20; struct edge{ int to,next,v; }edge[maxn*2]; int head[maxn],tot; int dis[maxn]; void addedge(int u,int v,int z){ edge[tot].to=v; edge[tot].next=head[u]; edge[tot].v=z; head[u]=tot++; } void init(){ tot=0; memset(head,-1,sizeof(head)); memset(dis,0,sizeof dis); } int fa[maxn][deg];//fa[i][j]表示結點i的第2^j個祖先 int dep[maxn];//深度陣列 void bfs(int root){ queue<int> que; dep[root]=0; fa[root][0]=root; que.push(root); while(!que.empty()){ int tmp=que.front(); que.pop(); for(int i=1;i<deg;i++) fa[tmp][i]=fa[fa[tmp][i-1]][i-1]; for(int i=head[tmp];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==fa[tmp][0]) continue; dis[v]=dis[tmp]+edge[i].v; dep[v]=dep[tmp]+1; fa[v][0]=tmp; que.push(v); } } } int lca(int u,int v){ if(dep[u]>dep[v]) swap(u,v); int hu=dep[u],hv=dep[v]; int tu=u,tv=v; for(int det=hv-hu,i=0;det;det>>=1,i++) if(det&1) tv=fa[tv][i]; if(tu==tv) return tu; for(int i=deg-1;i>=0;i--){ if(fa[tu][i]==fa[tv][i]) continue; tu=fa[tu][i]; tv=fa[tv][i]; } return fa[tu][0]; } int d(int u,int v){ return dis[u]+dis[v]-2*dis[lca(u,v)]; } int t,n,tt,q,x,y,z,u,v; int main() { rd(t);tt=0; while(t--){ init(); rd2(n,q); for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); addedge(y,x,z); } bfs(1); scanf("%d%d%d",&x,&y,&z); printf("Case #%d:\n",++tt); while(q--){ rd2(u,v); int l1=d(u,x)+z+d(v,y);//強行通過新邊 int l2=d(u,y)+z+d(v,x); int l=d(u,v);//原來在樹上的路徑 l1=min(l1,l2); if(l1<=l) printf("%d\n",l-l1); else printf("0\n"); } } return 0; } </span>