• [主席树][哈希][最短路]CF464E The Classic Problem


    题面

    https://codeforces.com/contest/464/problem/E

    https://www.luogu.com.cn/problem/CF464E

    分析

    高精度暴力跑最短路 $O(nlognx)$ ,考虑优化

    发现最短路中松弛操作所用的加法,在二进制串上所需要实现的就是区间清零和单点修改

    e.g. 01110+00100=10010

    考虑用线段树维护01串,找一段连续 1 区间可以用线段树二分解决,比较大小的时候可以用类似字符串哈希的做法来确定高位是否相同

    但时间复杂度 $O(nlogx)$ 空间复杂度 $O(n^2logx)$ 不能通过

    考虑到有许多共用节点,将线段树改为主席树

    区间清零可以通过建一个全零线段树,将需要清零的区间的父亲连到对应零区间,辅以一些回收节点的操作即可通过

    时间复杂度 $O(nlogx)$ 空间复杂度 $O(nlog^2x)$

    代码

    #include <iostream>
    #include <cstdio>
    #include <queue>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ll P=1e9+7;
    const int N=2e5+10;
    const int M=N*20;
    struct Graph {
        int v,w,nx;
    }g[2*N];
    int cnt,list[N],tcnt,root[N],f[N];
    struct Node {
        ll val;
        ull hash;
        int cnt,c[2];
        friend bool operator == (Node a,Node b) {return a.val==b.val&&a.hash==b.hash&&a.cnt==b.cnt;}
    }t[2*M];
    ll pw[N];
    ull hnum[N];
    bool vis[N];
    int n,m,inf,S,T,ans[N],acnt;
    
    void Add(int u,int v,int w) {g[++cnt]=(Graph){v,w,list[u]};list[u]=cnt;}
    
    void Update(int x) {
        t[x].cnt=t[t[x].c[0]].cnt+t[t[x].c[1]].cnt;
        t[x].val=(t[t[x].c[0]].val+t[t[x].c[1]].val)%P;
        t[x].hash=t[t[x].c[0]].hash+t[t[x].c[1]].hash;
    }
    
    void Build(int &x,int l,int r,int val) {
        if (!x) x=++tcnt;
        if (l==r) return t[x].cnt=val,t[x].val=val*pw[l],t[x].hash=val*hnum[l],void();
        int mid=l+r>>1;
        Build(t[x].c[0],l,mid,val);Build(t[x].c[1],mid+1,r,val);
        Update(x);
    }
    
    int Query(int x,int l,int r,int L,int R) {
        if (L<=l&&r<=R) return t[x].cnt;
        int mid=l+r>>1,ans=0;
        if (L<=mid) ans=Query(t[x].c[0],l,mid,L,R);
        if (mid<R) ans+=Query(t[x].c[1],mid+1,r,L,R);
        return ans;
    }
    
    int Search(int x,int l,int r,int k) {
        if (l==r) return l;
        int mid=l+r>>1;
        if (k>mid) return Search(t[x].c[1],mid+1,r,k);
        if (Query(t[x].c[0],l,mid,k,mid)==mid-k+1) return Search(t[x].c[1],mid+1,r,mid+1);
        return Search(t[x].c[0],l,mid,k);
    }
    
    bool S_CMP(int x,int y,int l,int r) {
        if (l==r) return t[x].cnt<t[y].cnt;
        int mid=l+r>>1;
        if (t[t[x].c[1]]==t[t[y].c[1]]) return S_CMP(t[x].c[0],t[y].c[0],l,mid);
        return S_CMP(t[x].c[1],t[y].c[1],mid+1,r);
    }
    
    void Link(int &x,int y,int l,int r,int L,int R) {
        if (L<=l&&r<=R) return x=y,void();
        int mid=l+r>>1,z=++tcnt;t[z]=t[x];
        if (L<=mid) Link(t[z].c[0],t[y].c[0],l,mid,L,R);
        if (mid<R) Link(t[z].c[1],t[y].c[1],mid+1,r,L,R);
        Update(x=z);
    }
    
    void S_Add(int &x,int l,int r,int k) {
        t[++tcnt]=t[x];x=tcnt;
        if (l==r) return t[x].val=pw[l],t[x].cnt=1,t[x].hash=hnum[l],void();
        int mid=l+r>>1;
        if (k<=mid) S_Add(t[x].c[0],l,mid,k);
        else S_Add(t[x].c[1],mid+1,r,k);
        Update(x);
    }
    
    struct Path {
        int id,rt;
        friend bool operator < (Path a,Path b) {return S_CMP(b.rt,a.rt,0,N-1);}
    };
    priority_queue<Path> q;
    
    void Dijkstra() {
        priority_queue<Path> q;
        while (!q.empty()) q.pop();
        for (int i=1;i<=n;i++) root[i]=inf;root[S]=root[0];q.push((Path){S,root[S]});
        while (!q.empty()) {
            int u=q.top().id;q.pop();
            if (vis[u]) continue;vis[u]=1;
            for (int i=list[u];i;i=g[i].nx) {
                int newz=root[u],l=Search(root[u],0,N-1,g[i].w),re=tcnt;
                S_Add(newz,0,N-1,l);
                if (g[i].w<l) Link(newz,root[0],0,N-1,g[i].w,l-1);
                if (S_CMP(newz,root[g[i].v],0,N-1)) f[g[i].v]=u,q.push((Path){g[i].v,root[g[i].v]=newz});
                else tcnt=re;
            }
        }
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1,u,v,x;i<=m;i++) scanf("%d%d%d",&u,&v,&x),Add(u,v,x),Add(v,u,x);
        scanf("%d%d",&S,&T);
        pw[0]=1;hnum[0]=1;for (int i=1;i<N;i++) pw[i]=(pw[i-1]<<1)%P,hnum[i]=hnum[i-1]*23;
        Build(root[0],0,N-1,0);Build(inf,0,N-1,1);
        Dijkstra();
        if (root[T]==inf) return printf("-1\n"),0;
        for (int x=T;x!=S;x=f[x]) ans[++acnt]=x;
        ans[++acnt]=S;
        printf("%lld\n%d\n",t[root[T]].val,acnt);
        for (int i=acnt;i;i--) printf("%d ",ans[i]);
    }
    View Code
  • 相关阅读:
    Kafka 数据丢失问题总结
    HTTP3
    CnetOS7 控制台方式启动
    Win32Exception (0x8009030C) —— 密码过期 —— Kerberos 异常
    WebAPI Tip #8: Working with Tasks & WebAPI Tip #7: Beautiful Message Handlers (转发)
    Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed DataIntensive Systems(转发)
    git commond —— git merge —— 模拟某次 merge 操作
    git commad —— git lsfiles —— 获取 文件 的修改信息
    Using async/await or task in web api controller (.net core)
    Chrome debugger for vscode (react 使用vscode 调试 :debugger for chrome 被弃用, 改用 JavaScript Debugger)
  • 原文地址:https://www.cnblogs.com/vagari/p/14605559.html
Copyright © 2020-2023  润新知