可持久化左偏树复杂度似乎不对?
查看原帖
可持久化左偏树复杂度似乎不对?
55459
ZhYic楼主2019/3/21 16:28

打了一发可持久化左偏树的k短路,#4、#11都MLE,下载孔爷的数据(#11)自测发现左偏树上节点个数非常巨大,约有1.2e7个点,不知是否因为我写错了。 改为随机堆后通过。 代码如下,如有不对请指出

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define Side(x) for(int i=p[x];i;i=nt[i])
using namespace std;
typedef pair<double,int> pdi;
const int N=100020,M=500020;
const double eps=1e-10;
int n,m,tot,e[M],nt[M],p[N];
double se,w[M];
struct Edge
{
    int u,v;
    double w;
    int id;
}edge[M];
inline void _add(int x,int y,double z){e[++tot]=y,nt[tot]=p[x],w[tot]=z,p[x]=tot;}
double dis[N];
inline bool dCmp(double a,double b){return a<b?(b-a<eps):(a-b<eps);}
int fa[N];
bool onT[M],vis[N];
priority_queue<pdi,vector<pdi>,greater<pdi> >q;
void dijkstra(int s)
{
    for(int i=1;i<=n;i++)dis[i]=INFINITY;
    dis[s]=0,q.push((pdi){0,s});
    while(!q.empty())
    {
        int fr=q.top().second;q.pop();
        if(vis[fr])continue;
        vis[fr]=true;
        Side(fr)
        {
            if(dis[e[i]]>dis[fr]+w[i])
            {
                dis[e[i]]=dis[fr]+w[i];
                q.push((pdi){dis[e[i]],e[i]});
            }
        }
    }
}
void dfs(int x)
{
    vis[x]=true;
    Side(x)
    {
        if(!vis[e[i]]&&dCmp(dis[e[i]],dis[x]+w[i]))
            dfs(e[i]),onT[i]=true;
    }
}
struct hpnode
{
    double key;
    int dis,v;
    hpnode *ch[2];
    hpnode(double _key,int _v):key(_key),dis(1),v(_v){ch[0]=ch[1]=nullptr;}
};
typedef hpnode* hptr;
typedef pair<double,hptr> pdh;
hptr h[N],recycle[N*200];
int tp;
priority_queue<pdh,vector<pdh>,greater<pdh> >q1;
hptr merge(hptr x,hptr y)
{
    if(!x||!y)return x?x:y;
//	cerr<<x<<' '<<y<<endl;
    if(x->key>y->key)swap(x,y);
    hptr cur=new hpnode(*x);
    recycle[++tp]=cur;
    cur->ch[1]=merge(cur->ch[1],y);
//	cerr<<"cur ch:"<<cur->ch[0]<<' '<<cur->ch[1]<<endl;
    if(cur->ch[0]&&cur->ch[0]->dis<cur->ch[1]->dis)swap(cur->ch[0],cur->ch[1]);
    cur->dis=cur->ch[1]->dis+1;
    return cur;
}
void buildT()
{
    memset(vis,0,sizeof(vis));
    dfs(n);
    memset(p,0,sizeof(p)),tot=0;
    for(int i=1;i<=m;i++)
        if(!onT[edge[i].id]&&dis[edge[i].u]<INFINITY)_add(edge[i].u,edge[i].v,edge[i].w);
        else fa[edge[i].u]=edge[i].v;
    for(int u=1;u<=n;u++)
    {
//		cerr<<u<<':';
        Side(u)
        {
//			cerr<<e[i]<<' ';
            h[u]=merge(h[u],recycle[++tp]=(new hpnode(dis[e[i]]+w[i]-dis[u],e[i])));
        }
//		cerr<<endl;
    }
    cerr<<tp<<endl;
    while(!q.empty())q.pop();
    for(int i=1;i<=n;i++)q.push((pdi){dis[i],i});
    while(!q.empty())
    {
        int tp=q.top().second;q.pop();
//		cerr<<tp<<' '<<fa[tp]<<' '<<h[tp]<<' '<<h[fa[tp]]<<endl;
        h[tp]=merge(h[tp],h[fa[tp]]);
    }
}
void solve()
{
    int ans=0;
    if(dis[1]<=se)se-=dis[1],ans++;
    if(h[1])q1.push((pdh){h[1]->key,h[1]});
    while(!q1.empty())
    {
        double enow=q1.top().first;
        hptr cur=q1.top().second;
//		cerr<<enow<<','<<se<<endl;
        if(se>=enow+dis[1])se-=enow+dis[1],ans++;
        else break;
        q1.pop();
        if(cur->ch[0])q1.push((pdh){enow+cur->ch[0]->key-cur->key,cur->ch[0]});
        if(cur->ch[1])q1.push((pdh){enow+cur->ch[1]->key-cur->key,cur->ch[1]});
        if(h[cur->v])q1.push((pdh){enow+h[cur->v]->key,h[cur->v]});
    }
    printf("%d",ans);
}
int main()
{
	freopen("11.in","r",stdin);
    scanf("%d%d%lf",&n,&m,&se);
    int ui,vi;double wi;
    for(int i=1;i<=m;i++)
        scanf("%d%d%lf",&ui,&vi,&wi),_add(vi,ui,wi),edge[i]={ui,vi,wi,tot};
    dijkstra(n);
    buildT();
    solve();
}
2019/3/21 16:28
加载中...