P5344 【XR-1】逛森林

题意:可以进行区间间互相连边与单点连边,求从某起点到所有点的最短距离。

先离线弄出树的形态,并保存可行的区间操作。

然后就是喜闻乐见的树剖+线段树优化了。

然而,毒瘤出题人把树剖卡成了不会tle便会mle。

我会说我考试时被卡成傻逼了么

于是预处理倍增进行连边即可,

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=5e4+10,M=13e5+10;
struct node{
    int u1,v1,u2,v2,w;node(){};
    node(int _u1,int _v1,int _u2,int _v2,int _w){
        u1=_u1,v1=_v1,u2=_u2;v2=_v2;w=_w;
    }
}ql[M];
int n,m,s,t,tot,cnt,lg[N],f[N],dis[M<<1],d[N<<1],vis[M<<1],fa[N][16],in[N][16],out[N][16];
priority_queue<pair<int,int> >q;vector<int> g[N<<1];vector<pair<int,int> >edge[M<<1];
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
inline void add(int x,int y,int z){
    edge[x].push_back(make_pair(y,z));
}
inline void dijkstra(){
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;q.push(make_pair(0,s));
    while(q.size()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;vis[x]=1;
        for(int i=0;i<edge[x].size();i++){
            int y=edge[x][i].first,z=edge[x][i].second;
            if(dis[y]>dis[x]+z){
                dis[y]=dis[x]+z;if(!vis[y]) q.push(make_pair(-dis[y],y));
            }
        }
    }
}
inline int get(int x){
    if(x==f[x]) return x;return f[x]=get(f[x]);
}
inline int lca(int x,int y){
    if(d[x]>d[y]) swap(x,y);
    for(int i=15;~i;i--) if(d[fa[y][i]]>=d[x]) y=fa[y][i];
    if(x==y) return x;
    for(int i=15;~i;i--) if(fa[y][i]!=fa[x][i]) y=fa[y][i],x=fa[x][i];
    return fa[x][0]; 
}
inline void dfs(int x,int fat){
    fa[x][0]=fat;d[x]=d[fat]+1;
    in[x][0]=out[x][0]=x;
    for(int i=1;i<=15;i++){fa[x][i]=fa[fa[x][i-1]][i-1];}
    for(int i=1;(1<<i)<=d[x];i++){
        in[x][i]=++cnt;out[x][i]=++cnt;
        add(in[x][i],in[x][i-1],0);
        add(out[x][i-1],out[x][i],0);
        add(in[x][i],in[fa[x][i-1]][i-1],0);
        add(out[fa[x][i-1]][i-1],out[x][i],0);
    }
    for(int i=0;i<g[x].size();i++){
        int y=g[x][i];if(y==fat) continue;
        dfs(y,x);
    }
}
inline void build(int v1,int u1,int w,int k){
    int j=0,u=u1,v;
    for(;(2<<(j))<=d[u1]-d[v1]+1;j++);
    int res=d[u1]-d[v1]+1-(1<<j);
    for(int i=20;~i;i--) if(res&(1<<i)) u=fa[u][i];
    if(k) v=in[u][j];else v=out[u][j];
    add(k?cnt:v,k?v:cnt,w);
    u=u1;if(k) v=in[u][j];else v=out[u][j];
    add(k?cnt:v,k?v:cnt,w);
}
int main(){
    n=read();m=read();s=read();cnt=n+1;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    for(int i=1;i<=m;i++){
        int k=read(),u1=read(),v1=read(),u2,v2,w;
        if(k==1){
            u2=read();v2=read();w=read();
            if(get(u1)!=get(v1)||get(u2)!=get(v2)) continue;
            ql[++t]=node(u1,v1,u2,v2,w);
        }
        else if(k==2){
            int fu=get(u1),fv=get(v1);w=read();
            if(fu==fv) continue;
            g[u1].push_back(v1);
            g[v1].push_back(u1);
            add(u1,v1,w);add(v1,u1,w);
            f[fu]=fv;
        }
    }
    for(int i=1;i<=n;i++) if(!d[i]) dfs(i,0);
    for(int i=1;i<=t;i++){
        int u1=ql[i].u1,v1=ql[i].v1,u2=ql[i].u2,v2=ql[i].v2,w=ql[i].w;
        int lc1=lca(u1,v1),lc2=lca(u2,v2);cnt++;
        build(lc1,u1,0,0);build(lc1,v1,0,0);
        build(lc2,u2,w,1);build(lc2,v2,w,1);
    }
    dijkstra();for(int i=1;i<=n;i++) printf("%d ",(dis[i]==0x3f3f3f3f)?-1:dis[i]);
    return 0;
}

 


 

然后发现BZOJ4699具有90%的相似度,顺手a了,代码也不放了,读入改下就行了。

不过发现榜首的大爷们都是一个log的,orzorz

 

posted @ 2019-05-08 12:56  小塘一点空明  阅读(224)  评论(0编辑  收藏  举报