• [BZOJ4699]树上的最短路(最短路+线段树)


    https://www.cnblogs.com/Gloid/p/10273902.html

    这篇文章已经从头到尾讲的非常清楚了,几乎没有什么需要补充的内容。

    首先$O(nlog^2 n)$的做法比较显然,倍增优化建图+最短路即可。

    然后利用“每个塌陷最多会被使用一次”的性质,为每个塌陷(边也看作一种塌陷)建一个点跑一个变体的Dijkstra就可以优化到$O((n+m)log n)$。

    这里讲下我最后一步的实现。

    为每个塌陷找未标记的点很简单,并查集f[i]表示离i最近的未被标记的祖先,每次标记i后f[i]=get(fa[i])即可。

    为每个点找未标记的塌陷相对复杂,分两种情况考虑。

    一是x是这个塌陷的LCA,这个很好处理,开个vector存储以每个点为LCA的所有塌陷即可。

    二是塌陷的一个端点在x子树内,一个在子树外。

    设x的子树的DFS序区间为[L,R]

    考虑每次取出“一个端点在x的子树中,另一个端点的DFS序尽量小”的未标号的塌陷,若此塌陷的另一个端点在L之前则说明这个塌陷过点x。

    更新完后再把这个塌陷删掉,直到取出的塌陷在L之后。同理,对“尽量大”的塌陷也做一遍,直到这个塌陷另一个端点DFS序在R之前。

    于是我们要支持的是,查询一个端点在某个区间中的所有塌陷的另一个端点最小/大值。

    线段树维护每个区间中的这个信息,同时在线段树的叶子上,用堆维护“以这个点为端点的所有塌陷的另一个端点”。

    由于尽量小和尽量大都要做一边,所以要开一个大根堆和一个小根堆。

    实现起来可能没有什么细节,只是要注意代码不要写残,自己证一遍复杂度,否则可能不小心就写成$O(nlog^2 n)$的了。

      1 #include<queue>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #define ls (x<<1)
      5 #define rs (ls|1)
      6 #define lson ls,L,mid
      7 #define rson rs,mid+1,R
      8 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
      9 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     10 typedef long long ll;
     11 using namespace std;
     12 
     13 const int N=250010,M=850010;
     14 ll inf=1e15;
     15 bool tag[M],b[M];
     16 ll dis[M];
     17 int n,m,S,u,v,w,cnt,tot,tim;
     18 int pos[N],f[N],L[N],R[N],dep[N],fa[N][20];
     19 int h[N],to[N<<1],nxt[N<<1],mn[N<<2],mn1[N<<2],mx[N<<2],mx1[N<<2];
     20 struct E{ int L1,R1,L2,R2,w; }e[M];
     21 vector<int>ve[N];
     22 
     23 struct P{ int id,s; };
     24 bool operator <(const P &a,const P &b){ return a.s<b.s; }
     25 struct Cmp{ bool operator ()(const P &a,const P &b){ return a.s>b.s; } };
     26 priority_queue<P,vector<P>,Cmp>Q1[N];
     27 priority_queue<P>Q2[N];
     28 
     29 struct D{ int x; ll d; };
     30 bool operator <(const D &a,const D &b){ return a.d>b.d; }
     31 priority_queue<D>Q;
     32 
     33 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
     34 int get(int x){ return f[x]==x ? x : f[x]=get(f[x]); }
     35 
     36 void dfs(int x){
     37     dep[x]=dep[fa[x][0]]+1; L[x]=++tim; pos[tim]=x;
     38     rep(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1];
     39     For(i,x) if ((k=to[i])!=fa[x][0]) fa[k][0]=x,dfs(k);
     40     R[x]=tim;
     41 }
     42 
     43 int Lca(int x,int y){
     44     if (dep[x]<dep[y]) swap(x,y);
     45     int t=dep[x]-dep[y];
     46     for (int i=19; ~i; i--) if (t&(1<<i)) x=fa[x][i];
     47     if (x==y) return x;
     48     for (int i=19; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
     49     return fa[x][0];
     50 }
     51 
     52 void upd(int x){
     53     if (mn1[ls]<mn1[rs]) mn[x]=mn[ls],mn1[x]=mn1[ls]; else mn[x]=mn[rs],mn1[x]=mn1[rs];
     54     if (mx1[ls]>mx1[rs]) mx[x]=mx[ls],mx1[x]=mx1[ls]; else mx[x]=mx[rs],mx1[x]=mx1[rs];
     55 }
     56 
     57 void build(int x,int L,int R){
     58     if (L==R){
     59         int p=pos[L]; mn1[x]=n+1; mx1[x]=-1;
     60         if (!Q1[p].empty()) mn[x]=Q1[p].top().id,mn1[x]=Q1[p].top().s;
     61         if (!Q2[p].empty()) mx[x]=Q2[p].top().id,mx1[x]=Q2[p].top().s;
     62         return;
     63     }
     64     int mid=(L+R)>>1; build(lson); build(rson); upd(x);
     65 }
     66 
     67 void que(int x,int L,int R,int l,int r,bool k,int &s,int &s1){
     68     if (L==l && r==R){
     69         if (!k) s=mn[x],s1=mn1[x]; else s=mx[x],s1=mx1[x];
     70         return;
     71     }
     72     int mid=(L+R)>>1;
     73     if (r<=mid) que(lson,l,r,k,s,s1);
     74     else if (l>mid) que(rson,l,r,k,s,s1);
     75         else{
     76             int a,a1,b,b1;
     77             que(lson,l,mid,k,a,a1); que(rson,mid+1,r,k,b,b1);
     78             if (!k){ if (a1<b1) s=a,s1=a1; else s=b,s1=b1; }
     79                 else { if (a1>b1) s=a,s1=a1; else s=b,s1=b1; }
     80         }
     81 }
     82 
     83 void del(int x,int L,int R,int p,bool k){
     84     if (L==R){
     85         p=pos[p];
     86         if (!k){
     87             Q1[p].pop(); mn[x]=0; mn1[x]=n+1;
     88             if (!Q1[p].empty()) mn[x]=Q1[p].top().id,mn1[x]=Q1[p].top().s;
     89         }else{
     90             Q2[p].pop(); mx[x]=0; mx1[x]=-1;
     91             if (!Q2[p].empty()) mx[x]=Q2[p].top().id,mx1[x]=Q2[p].top().s;
     92         }
     93         return;
     94     }
     95     int mid=(L+R)>>1;
     96     if (p<=mid) del(lson,p,k); else del(rson,p,k);
     97     upd(x);
     98 }
     99 
    100 void solve1(int x){
    101     int u=e[x].L2,v=e[x].R2,lca=Lca(u,v);
    102     u=f[u]; v=f[v];
    103     while (dep[u]>=dep[lca] || dep[v]>=dep[lca]){
    104         if (!u && !v) break;
    105         if (dep[u]<dep[v]) swap(u,v);
    106         if (!tag[u]) dis[u]=min(dis[u],dis[x+n]),Q.push((D){u,dis[u]});
    107         tag[u]=1; u=f[u]=get(fa[u][0]);
    108     }
    109 }
    110 
    111 void solve2(int x){
    112     int ed=ve[x].size()-1;
    113     rep(i,0,ed){
    114         int k=ve[x][i];
    115         if (!tag[k+n]) tag[k+n]=1,dis[k+n]=min(dis[k+n],dis[x]+e[k].w),Q.push((D){k+n,dis[k+n]});
    116     }
    117     while (1){
    118         int mn,mn1,mx,mx1;
    119         que(1,1,n,L[x],R[x],0,mn,mn1);
    120         que(1,1,n,L[x],R[x],1,mx,mx1);
    121         if (mn1>=L[x]) mn=0;
    122         if (mx1<=R[x]) mx=0;
    123         if (!mn && !mx) break;
    124         if (mn){
    125             if (!tag[mn+n]) dis[mn+n]=min(dis[mn+n],dis[x]+e[mn].w),Q.push((D){mn+n,dis[mn+n]});
    126             tag[mn+n]=1; del(1,1,n,L[e[mn].L1]+L[e[mn].R1]-mn1,0);
    127         }
    128         if (mx){
    129             if (!tag[mx+n]) dis[mx+n]=min(dis[mx+n],dis[x]+e[mx].w),Q.push((D){mx+n,dis[mx+n]});
    130             tag[mx+n]=1; del(1,1,n,L[e[mx].L1]+L[e[mx].R1]-mx1,1);
    131         }
    132     }
    133 }
    134 
    135 void Dij(){
    136     rep(i,1,n+tot) dis[i]=inf; dis[S]=0; Q.push((D){S,0}); tag[S]=1;
    137     while (!Q.empty()){
    138         int x=Q.top().x; Q.pop();
    139         if (b[x]) continue;
    140         b[x]=1;
    141         if (x>n) solve1(x-n); else solve2(x);
    142     }
    143 }
    144 
    145 int main(){
    146     freopen("bzoj4699.in","r",stdin);
    147     freopen("bzoj4699.out","w",stdout);
    148     scanf("%d%d%d",&n,&m,&S);
    149     rep(i,2,n) scanf("%d%d%d",&u,&v,&w),e[++tot]=(E){u,u,v,v,w},e[++tot]=(E){v,v,u,u,w},add(u,v),add(v,u);
    150     dfs(1);
    151     rep(i,1,n) f[i]=i;
    152     rep(i,1,m) tot++,scanf("%d%d%d%d%d",&e[tot].L2,&e[tot].R2,&e[tot].L1,&e[tot].R1,&e[tot].w);
    153     rep(i,1,tot){
    154         int u=e[i].L1,v=e[i].R1,lca=Lca(u,v);
    155         ve[lca].push_back(i);
    156         Q1[u].push((P){i,L[v]}); Q2[u].push((P){i,L[v]});
    157         Q1[v].push((P){i,L[u]}); Q2[v].push((P){i,L[u]});
    158     }
    159     build(1,1,n); Dij();
    160     rep(i,1,n) printf("%lld
    ",dis[i]);
    161     return 0;
    162 }
  • 相关阅读:
    脱壳实践之手动构造输入表
    脱壳实践之寻找OEP——堆栈平衡法
    脱壳实践之寻找OEP——两次内存断点法
    PE文件格式详解(八)
    PE文件格式详解(七)
    PE文件格式详解(六)
    Eclipse 安装 Maven 插件(图文解说)
    在线图片压缩后以ImageIO 流的形式 设置大小显示指定页面
    Android-studio开发 快捷键
    简明 Git 命令速查表(中文版)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10276352.html
Copyright © 2020-2023  润新知