bzoj 4699 树上最短路 - 最短路 - 线段树 - 并查集

过了这么长时间都快忘了怎么做了……
考虑修改一下dijkstra算法的过程,我们不是每次把一个点的dist放到堆里,而是把所有每条边的起点的dist+边权放到堆里,这样的好处是,在这种出边边权相同的情况下,可以保证每个点只会被更新一次。
这个题的性质是,一个下水道只会在第一次访问的时候用到,因此先预处理一个点被哪些下水道覆盖,然后每次更新一个点就把所有这样的区间拿出来,然后更新这些区间能够到达的没有被访问过的点,然后更新这些点的答案然后删除。
后一个问题可以用并查集维护,前面一个,被下水道覆盖,等价于,要么是这个路径的LCA,或者一个点在子树内一个点在子树外,前者好维护,后者考虑线段树,每个叶子x维护每条路径起点dfs序是x终点的dfs序有哪些,然后每个区间维护终点dfs序的最小和最大值,然后每次查询最小最大值看是否在询问区间之外,然后删除即可,这样就能保证每个区间只会被用来更新常数次,复杂度一个log(真神奇)。树边本质上也是下水道,不需要特殊处理。
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<utility>
#include<queue>
#define gc getchar()
#define N 300000
#define mp make_pair
#define fir first
#define sec second
#define lint long long
#define LOG 21
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct node{
    int x,y;lint w;
    node(int _x=0,int _y=0,lint _w=0)
    {   x=_x,y=_y,w=_w; }
    inline bool operator<(const node &n)const
    {   return w>n.w;    }
};
struct edges{
    int to,pre,wgt;
}e[N<<1];int h[N],etop,vs[N],vt[N],fa[N],Log[N],dfc,l1[N],l2[N];
lint ans[N];priority_queue<node> q;int up[N][LOG],d[N],r1[N];
vector<pii> v[N];vector<int> cz[N];int in[N],out[N],r2[N],c[N];
inline int add_edge(int u,int v,int w)
{   return e[++etop].to=v,e[etop].wgt=w,e[etop].pre=h[u],h[u]=etop; }
struct segment{
    int l,r;pii mn,mx;segment *ch[2];
}*rt;
inline int push_up(segment* &rt)
{
    return rt->mn=min(rt->ch[0]->mn,rt->ch[1]->mn),
        rt->mx=max(rt->ch[0]->mx,rt->ch[1]->mx),0;
}
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r;int mid=(l+r)>>1;rt->mn=mp(N+1,0),rt->mx=mp(0,0);
    if(l==r) return (v[l].size()?rt->mn=v[l][0],rt->mx=v[l][vt[l]],0:0);
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);
}
int update(segment* &rt,int p,int k)//k=0:del min
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(l==r){
        if(k) vt[p]--;else vs[p]++;
        if(vs[p]<=vt[p]) rt->mx=v[p][vt[p]],rt->mn=v[p][vs[p]];
        else rt->mx=mp(0,0),rt->mn=mp(N+1,0);return 0;
    }
    return update(rt->ch[p>mid],p,k),push_up(rt);
}
int show(segment* &rt)
{
    pii mn=rt->mn,mx=rt->mx;int l=rt->l,r=rt->r;
    debug(l)sp,debug(r)sp,debug(mn.fir)sp,debug(mn.sec)sp,debug(mx.fir)sp,debug(mx.sec)ln;
    if(l<r) return show(rt->ch[0]),show(rt->ch[1]);return 0;
}
pii query(segment* &rt,int s,int t,int k)//k=0:query:min
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return k?rt->mx:rt->mn;pii ans=k?mp(0,0):mp(N+1,0);
    if(s<=mid) k?ans=max(ans,query(rt->ch[0],s,t,k)):ans=min(ans,query(rt->ch[0],s,t,k));
    if(mid<t) k?ans=max(ans,query(rt->ch[1],s,t,k)):ans=min(ans,query(rt->ch[1],s,t,k));
    return ans;
}
inline int findf(int x)
{
    int fx=x,y;while(fx^fa[fx]) fx=fa[fx];
    while(x^fx) y=fa[x],fa[x]=fx,x=y;return x;
}
int dfs(int x,int fa)
{
    up[x][0]=fa,d[x]=d[fa]+1,in[x]=++dfc;
    for(int i=1;i<=Log[d[x]];i++)
        up[x][i]=up[up[x][i-1]][i-1];
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^fa) dfs(y,x);
    return out[x]=dfc;
}
inline int getLCA(int x,int y)
{
    if(d[x]<d[y]) swap(x,y);
    for(int i=Log[d[x]];i>=0;i--)
        if(d[up[x][i]]>=d[y]) x=up[x][i];
    if(x==y) return x;
    for(int i=Log[d[x]];i>=0;i--)
        if(up[x][i]^up[y][i]) x=up[x][i],y=up[y][i];
    return up[x][0];
}
inline int ins(int x,lint w)
{
//  debug(x)ln;
    for(int i=h[x];i;i=e[i].pre) q.push(node(e[i].to,e[i].to,w+e[i].wgt));
    for(int i=0;i<(int)cz[x].size();i++) q.push(node(l2[cz[x][i]],r2[cz[x][i]],w+c[cz[x][i]]));
    for(int i=query(rt,in[x],out[x],0).sec;i&&in[l1[i]]<in[x];i=query(rt,in[x],out[x],0).sec)
        update(rt,in[r1[i]],0),q.push(node(l2[i],r2[i],w+c[i]));
//  cerr<<"----"<<endl;
    for(int i=query(rt,in[x],out[x],1).sec;i&&in[r1[i]]>out[x];i=query(rt,in[x],out[x],1).sec)
        update(rt,in[l1[i]],1),q.push(node(l2[i],r2[i],w+c[i]));
//  debug(x)ln ln;
    return ans[x]=w,0;
}
int main()
{
//  freopen("a.in","r",stdin),freopen("std.out","w",stdout);
    int n=inn(),m=inn(),k=inn();
    for(int i=1,u,v,w;i<n;i++)
        u=inn(),v=inn(),w=inn(),add_edge(u,v,w),add_edge(v,u,w);
    for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    up[1][0]=fa[n+1]=n+1,d[1]=1,dfs(1,0);for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
        l2[i]=inn(),r2[i]=inn(),l1[i]=inn(),r1[i]=inn(),
        c[i]=inn(),cz[getLCA(l1[i],r1[i])].push_back(i);
    for(int i=1;i<=m;i++)
    {
        if(in[l1[i]]>in[r1[i]]) swap(l1[i],r1[i]);
        v[in[l1[i]]].push_back(mp(in[r1[i]],i)),
        v[in[r1[i]]].push_back(mp(in[l1[i]],i));
    }
    for(int i=1;i<=n;i++) sort(v[i].begin(),v[i].end()),vs[i]=0,vt[i]=(int)v[i].size()-1;
    build(rt,1,n),ans[k]=0,ins(k,0),fa[k]=up[k][0];
    while(!q.empty())
    {
        int x=q.top().x,y=q.top().y,c=getLCA(x,y);lint w=q.top().w;q.pop();
//      debug(x)sp,debug(y)sp,debug(w)ln;
        for(int t=findf(x);d[t]>=d[c];t=findf(fa[t]=up[t][0])) ins(t,w);
        for(int t=findf(y);d[t]>=d[c];t=findf(fa[t]=up[t][0])) ins(t,w);
    }
    for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);return 0;
}

猜你喜欢

转载自blog.csdn.net/mys_c_k/article/details/81141340
今日推荐