CF :K 一个含n条边的带权无向连通图,q次查询,每次查询两点间的最短距离。...
生活随笔
收集整理的這篇文章主要介紹了
CF :K 一个含n条边的带权无向连通图,q次查询,每次查询两点间的最短距离。...
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:給你一個(gè)含n條邊的帶權(quán)無向連通圖,q次查詢,每次查詢兩點(diǎn)間的最短距離。
思路:LCA+思維。
設(shè)a,b兩點(diǎn)間的距離為f(a,b) 則f(a,b)=dis[a]+dis[b]-2*dis[lca(a,b)];
由于n條邊,因此我們先任取一條邊,設(shè)這條邊為X,Y,權(quán)值為Z,設(shè)查詢的點(diǎn)為x,y,則答案為
min(f(a,b),f(a,X)+f(b,X),f(a,Y)+f(b,Y),f(a,X)+f(b,Y)+Z,f(a,Y)+f(b,X)+Z);
#include<bits/stdc++.h> #define lson (i<<1) #define rson (i<<1|1)using namespace std; typedef long long ll; const int N =1e5+5;struct node {int u,v,next;int id,f;ll w; }edge[N*2];struct node1 {int l,r;ll w;ll lz; }tr[N<<2];int tot,head[N]; int n,q; int anc[N<<1][20];int dfn; int dfns[N*2]; int dep[N*2]; int pos[N]; int inde[N]; int L[N]; int R[N]; int clo;int to[N]; int vis[N]; ll ww[N];int uu,vv; ll cost; int huan; int idd;void init() {tot=0;memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));memset(inde,-1,sizeof(inde));memset(pos,-1,sizeof(pos));clo=0; huan=0; idd=0; dfn=0; /// dfn竟然沒清零 MMP }void add(int u,int v,ll w,int id) {edge[++tot].u=u; edge[tot].v=v; edge[tot].id=id; edge[tot].w=w; edge[tot].f=0;edge[tot].next=head[u]; head[u]=tot; }void dfs1(int u,int fa) {if(vis[u]){uu=fa; vv=u; huan=1; return ;}vis[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==fa) continue;dfs1(v,u);} }void dfs2(int u,int deep) /// dfs序 {//cout<<" u "<<u<<" deep "<<deep<<endl;dfns[dfn]=u; dep[dfn]=deep; pos[u]=dfn++;L[u]=++clo;inde[u]=L[u]; /// 記錄u在線段樹中的位置for(int i=head[u];i!=-1;i=edge[i].next){if(edge[i].f) continue; /// 如果是標(biāo)記的邊跳過int v=edge[i].v;if(pos[v]==-1){to[edge[i].id]=v; /// 表示這條邊指向哪個(gè)點(diǎn)?dfs2(v,deep+1);dfns[dfn]=u; dep[dfn++]=deep;}}R[u]=clo; }void init_RMQ(int n) /// dfn {for(int i=1;i<=n;++i) anc[i][0]=i;for(int j=1;(1<<j)<=n;++j)for(int i=1;i+(1<<j)-1<=n;++i){if(dep[anc[i][j-1]]<dep[anc[i+(1<<(j-1))][j-1]]) anc[i][j]=anc[i][j-1];else anc[i][j]=anc[i+(1<<(j-1))][j-1];} }inline int RMQ(int L,int R) {int k=0;while(1<<(k+1)<=R-L+1) ++k;if(dep[anc[L][k]]<dep[anc[R-(1<<k)+1][k]]) return anc[L][k];return anc[R-(1<<k)+1][k]; }inline int LCA(int u,int v) {if(pos[u]>pos[v]) return dfns[RMQ(pos[v],pos[u])];return dfns[RMQ(pos[u],pos[v])]; }void push_up(int i) {tr[i].w=tr[lson].w+tr[rson].w; }void push_down(int i) {if(tr[i].lz){ /// 查詢只有點(diǎn)查詢,所以不必更新區(qū)間點(diǎn)的sumll &lz=tr[i].lz;tr[lson].lz+=lz; tr[rson].lz+=lz;tr[lson].w+=lz; tr[rson].w+=lz;lz=0;} }void build(int i,int l,int r) {tr[i].l=l; tr[i].r=r; tr[i].w=0; tr[i].lz=0;if(l==r) return ;int mid=(l+r)>>1;build(lson,l,mid);build(rson,mid+1,r); }void update(int i,int l,int r,ll w) {if(tr[i].l==l&&tr[i].r==r){tr[i].lz+=w; tr[i].w+=w;return ;}push_down(i);int mid=(tr[i].l+tr[i].r)>>1;if(r<=mid) update(lson,l,r,w);else if(l>mid ) update(rson,l,r,w);else{update(lson,l,mid,w);update(rson,mid+1,r,w);}push_up(i); }ll query(int i,int aim) {if(tr[i].l==tr[i].r&&tr[i].l==aim){return tr[i].w;}push_down(i);int mid=(tr[i].l+tr[i].r)>>1;if(aim<=mid) return query(lson,aim);else return query(rson,aim); }ll getans(int u,int v) {int lca=LCA(u,v);ll sum1,sum2,sum3;sum1=query(1,L[u]); sum2=query(1,L[v]);sum3=query(1,L[lca]);return sum1+sum2-sum3*2; }int main() {int T;int u,v,op;ll w;scanf("%d",&T);while(T--){scanf("%d %d",&n,&q);init();for(int i=1;i<=n;i++){scanf("%d %d %lld",&u,&v,&w);add(u,v,w,i);add(v,u,w,i);ww[i]=w;}dfs1(1,-1);/// 第一遍dfs 先找到環(huán)中的任意一條邊for(int i=1;i<=tot;i++){ /// 給邊打上標(biāo)記if((edge[i].u==uu&&edge[i].v==vv)||(edge[i].u==vv&&edge[i].v==uu)){edge[i].f=1;idd=edge[i].id;cost=edge[i].w;}}dfs2(1,0);/*cout<<"dfn "<<dfn<<endl;cout<<uu<<" *** "<<vv<<endl;for(int i=1;i<=n;i++){cout<<"l "<<L[i]<<" r "<<R[i]<<endl;}*/init_RMQ(dfn);build(1,1,n); /// 以dfs的遍歷出的 L,R 建樹 那么接下來就是一個(gè)區(qū)間更新,單點(diǎn)查詢的問題了for(int i=1;i<=n;i++){if(i==idd) continue;u=to[i];update(1,L[u],R[u],ww[i]);}/*for(int i=1;i<=n;i++){ll tmp=query(1,L[i]);cout<<" dis "<<tmp<<endl;}*/while(q--){scanf("%d %d",&u,&v);ll ans=getans(u,v);ans=min(ans,getans(uu,u)+getans(vv,v)+cost); /// 經(jīng)過標(biāo)記的路的兩個(gè)不同的方向。ans=min(ans,getans(uu,v)+getans(vv,u)+cost);printf("%lld\n",ans);}}return 0; } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/shuaihui520/p/10439993.html
總結(jié)
以上是生活随笔為你收集整理的CF :K 一个含n条边的带权无向连通图,q次查询,每次查询两点间的最短距离。...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在 iPhone 12 上登录 Appl
- 下一篇: Math、Date内置对象方法整理