• Luogu P4768 [NOI2018]归程


    题目链接

    题目大意:一个n个节点、m条边的无向连通图。我们依次用l,a描述一条边的长度、海拔。对于接下来Q个询问,每一天Yazid都会告诉你他的出发点v,Yazid需要从v到1,以及当天的水位线p,所有海拔不超过水位线的边都是有积水的。

    每一个询问,Yazid在出发点都拥有一辆车。这辆车不能经过有积水的边。Yazid可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。

    需要特殊说明的是,第二天车会被重置,这意味着:

    • 车会在新的出发点被准备好。
    • Yazid不能利用之前在某处停放的车。

    最小化Yazid的步行距离,强制在线

    NOI2018的毒瘤题目,本以为自己能凎出来,但是还是看了题解,妙啊

    对于最优解(1,v)这条路径中,一定存在一个点u,使得(1,u)全为步行,(u,v)全为开车,由此我们可以暴力枚举分界点u

    但是怎么处理积水的边呢?这是一个经典的问题,形如从点v开始只经过边权小于(或大于)x的路径所能到达节点集合,可以用kruskal重构树。


    在kruskal重构树中,从点v倍增向上跳,找到深度最小的一个点权大于p的节点,p的子树就是v可达的子集。

    预处理出1到所有点的最短路,再预处理出重构树里每个子树内到1最短节点的距离就OK了。

    还有一件事,关于SPFA,它死了

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    inline int read() {
        char ch;
        int bj=1;
        while(!isdigit(ch=getchar()))
            bj=(ch=='-')?-1:1;
        int res=ch^(3<<4);
        while(isdigit(ch=getchar()))
            res=(res<<1)+(res<<3)+(ch^(3<<4));
        return res*bj;
    }
    void printnum(int x) {
        if(x>9)printnum(x/10);
        putchar(x%10+'0');
    }
    inline void print(int x,char ch) {
        if(x<0) {
            putchar('-');
            x=-x;
        }
        printnum(x);
        putchar(ch);
    }
    const int MAXN=2e5+5;
    int n,m,tot,cnt,g[MAXN<<1][25],cnt1;
    int lastans;
    int a[MAXN<<1];
    int h[MAXN];
    int h1[MAXN<<1];
    struct Edge {
        int to,nxt,v;
    } w[MAXN<<2]; //图里的边
    struct node {
        int to,nxt;
    } w1[MAXN<<2]; //树里的边
    int d[MAXN<<1];
    bool vst[MAXN];//最短路
    int prt[MAXN<<1];//并查集
    int f[MAXN<<1];
    priority_queue<pair<int,int> >q;
    struct node1 {
        int x,y,a;
        inline bool operator < (node1 b)const {
            return a>b.a;
        }
    } e[MAXN<<1];
    inline void AddEdge(int x,int y,int z) {//建图边
        w[++cnt].to=y;
        w[cnt].nxt=h[x];
        w[cnt].v=z;
        h[x]=cnt;
    }
    inline void AddEdge2(int x,int y) {//建树边
        w1[++cnt1].to=y;
        w1[cnt1].nxt=h1[x];
        h1[x]=cnt1;
    }
    inline void dijkstra(int v0) {
        memset(d,0x3f,sizeof(d));
        memset(vst,0,sizeof(vst));
        d[v0]=0;
        q.push(make_pair(0,v0));
        while(!q.empty()) {
            int x=q.top().second;
            q.pop();
            if(vst[x])continue;
            vst[x]=1;
            for(int i=h[x]; i; i=w[i].nxt) {
                int v=w[i].to;
                if(d[v]>d[x]+w[i].v) {
                    d[v]=d[x]+w[i].v;
                    q.push(make_pair(-d[v],v));
                }
            }
        }
    }
    int GetFather(int x) {
        return x^prt[x]?prt[x]=GetFather(prt[x]):x;
    }
    inline void kruskal() {
        sort(e+1,e+m+1);
        tot=n;
        for(int i=1; i<=n; i++)prt[i]=i;
        for(int i=1; i<=m; i++) {
            int x=GetFather(e[i].x),y=GetFather(e[i].y);
            if(x^y) {
                tot++;
                a[tot]=e[i].a;
                prt[x]=prt[y]=prt[tot]=tot;
                AddEdge2(x,tot);
                AddEdge2(tot,x);
                AddEdge2(y,tot);
                AddEdge2(tot,y);
            }
        }
    }
    inline void DFS(int x,int fa) {
        f[x]=d[x];
        g[x][0]=fa;
        for(int i=h1[x]; i; i=w1[i].nxt) {
            int v=w1[i].to;
            if(v==fa)continue;
            DFS(v,x);
            f[x]=min(f[x],f[v]);
        }
    }
    inline void ST() {
        for(int j=1; (1<<j)<=tot; j++)
            for(int i=1; i<=tot; i++)
                if(g[i][j-1])
                    g[i][j]=g[g[i][j-1]][j-1];
    }
    inline void clear() {
        memset(h,0,sizeof(h));
        memset(w,0,sizeof(w));
        memset(h1,0,sizeof(h1));
        memset(w1,0,sizeof(w1));
        cnt=cnt1=0;
        memset(g,0,sizeof(g));
        memset(prt,0,sizeof(prt));
        lastans=0;
    }
    inline void Solve() {
        n=read();
        m=read();
        int x,y,z;
        for(int i=1; i<=m; i++) {
            e[i].x=read();
            e[i].y=read();
            z=read();
            e[i].a=read();
            AddEdge(e[i].x,e[i].y,z);
            AddEdge(e[i].y,e[i].x,z);
        }
        dijkstra(1);
        kruskal();
        DFS(tot,0);
        ST();
        int Q=read();
        int k=read(),s=read();
        while(Q--) {
            x=(read()+k*lastans-1)%n+1;
            y=(read()+k*lastans)%(s+1);
            for(int i=24; ~i; i--)
                if(g[x][i]&&a[g[x][i]]>y)x=g[x][i];
            print(lastans=f[x],'
    ');
        }
    }
    signed main() {
        int T=read();
        while(T--) {
            clear();
            Solve();
        }
        return 0;
    }
  • 相关阅读:
    typescript
    js-解决安卓手机软键盘弹出后,固定定位布局被顶上移问题
    vue
    js
    Object.assgin基本知识与相关深浅拷贝
    js-工具方法(持续更新)
    vue
    vue
    git
    css
  • 原文地址:https://www.cnblogs.com/soledadstar/p/11553336.html
Copyright © 2020-2023  润新知