zoukankan      html  css  js  c++  java
  • 「NOI2018」归程

    ## [「NOI2018」归程](https://loj.ac/problem/2718)

    题目描述
    本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 >(1) 个节点、 (m) 条边的无向连通图(节点的编号从 (1)(n) )。我们依次用 (l, a) 描述一
    条边的长度、海拔。 作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不
    可避免 的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水>位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。

    Yazid 是一名来自魔力之都的(OIer),刚参加完(ION2018) 的他将踏上归程,回到他 温暖的家。 Yazid 的家恰好在魔力之都的 (1) 号节点。对于接下来 (Q) 天,每一天Yazid 都会告诉你他的出发点 (v) ,以及当天的水位线 (p) 。 每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。 Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。 需要特殊说明的是,第二天车会被重置,这意味着:车会在新的出发点被准备好。Yazid 不能利用之前在某处停放的车。

    Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。 本题的部分测试点强制在线。


    ### 解题思路 :

    观察发现,对于询问点能通过没有水的边能到达的点 (u),在此下车的答案就是 (1) 到它的最短路 (dis_u).

    此时有一个很显然的离线做法,将询问的 (p) 从大到小排序,依次加边维护没有水的边的联通块,并维护每一个块的 (dis) 最小值即可

    考虑强制在线就是把并查集可持久化,于是大力码一棵主席树即可以 (O(nlog^2n)) 的复杂度解决此题.

    考虑到要可持久化的数组比较多,常数有点大,可以把联通块的 (Mindis) 以取反的形式存在 (fa[rt]) 上,可以少可持久化一个数组.


    ```cpp #include #define inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if(f) x = -x; } const int N = 700005, M = 1200005; int n, m, Q, K, S;

    int a[M], b[M], nxt[M], head[N], dis[N], cnt;
    struct Node{
    ll d, id;
    bool operator < (const Node &A) const{ return d > A.d; }
    }; priority_queue pq;
    inline void add(int x, int y, int z){
    a[++cnt] = y, b[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
    }
    inline void dijkstra(){
    for(int i = 1; i <= n; i++) dis[i] = inf / 3;
    dis[1] = 0, pq.push((Node){0, 1});
    while(!pq.empty()){
    Node now = pq.top(); pq.pop();
    int val = now.d, u = now.id;
    if(dis[u] < val) continue;
    for(int p = head[u]; p; p = nxt[p]){
    int v = a[p];
    if(dis[u] + b[p] < dis[v]){
    dis[v] = dis[u] + b[p];
    pq.push((Node){dis[v], v});
    }
    }
    }
    }

    struct PersistableArray{
    int rt[N], s[M25], lc[M25], rc[M*25], size;
    inline void clear(){
    for(int i = 1; i <= size; i++) lc[i] = rc[i] = s[i] = 0;
    for(int i = 1; i <= n; i++) rt[i] = 0; size = 0;
    }
    inline void build(int &u, int l, int r, int *a){
    u = ++size;
    if(l == r) return (void) (s[u] = a[l]);
    int mid = l + r >> 1;
    build(lc[u], l, mid, a), build(rc[u], mid + 1, r, a);
    }
    inline void Ins(int &u, int pr, int l, int r, int pos, int v){
    u = ++size;
    if(l == r) return (void) (s[u] = v);
    int mid = l + r >> 1;
    lc[u] = lc[pr], rc[u] = rc[pr];
    if(pos <= mid) Ins(lc[u], lc[pr], l, mid, pos, v);
    else Ins(rc[u], rc[pr], mid + 1, r, pos, v);
    }
    inline int query(int u, int l, int r, int pos){
    if(l == r) return s[u];
    int mid = l + r >> 1;
    if(pos <= mid) return query(lc[u], l, mid, pos);
    else return query(rc[u], mid + 1, r, pos);
    }
    inline int get(int u, int pos){ return query(rt[u], 1, n, pos); }
    inline void mof(int u, int pos, int v){ Ins(rt[u], rt[u], 1, n, pos, v); }
    }fa, sz;

    namespace Dsu{
    int a[N], ban;
    inline int ask(int now, int x){
    int p = fa.get(now, x);
    if(p <= 0) return x; else return ask(now, p);
    }
    inline void unite(int x, int y){
    int p = ask(ban, x), q = ask(ban, y);
    if(p == q) return;
    int szp = sz.get(ban, p), szq = sz.get(ban, q);
    if(szp > szq) swap(p, q);
    int vap = fa.get(ban, p), vaq = fa.get(ban, q);
    fa.mof(ban, p, q), fa.mof(ban, q, Max(vap, vaq));
    sz.mof(ban, q, szp + szq);
    }
    inline void addban(){
    fa.rt[ban+1] = fa.rt[ban];
    sz.rt[ban+1] = sz.rt[ban], ban++;
    }
    inline void prepare(){
    ban = 0;
    for(int i = 1; i <= n; i++) a[i] = -dis[i];
    fa.build(fa.rt[0], 1, n, a);
    for(int i = 1; i <= n; i++) a[i] = 1;
    sz.build(sz.rt[0], 1, n, a);
    }
    }

    int hs[N], c[N];
    struct Edge{ int x, y, a; } e[M];
    inline bool cmp(Edge A, Edge B){ return A.a < B.a; }
    inline void solve(int l, int r){
    Dsu::addban();
    for(int i = l; i <= r; i++) hs[i] = Dsu::ban;
    for(int i = l; i <= r; i++) Dsu::unite(e[i].x, e[i].y);
    }
    inline void BuildDsu(){
    sort(e + 1, e + m + 1, cmp), e[0].a = e[m+1].a = -1;
    Dsu::prepare();
    for(int i = m, r; i >= 1; i--){
    if(e[i].a != e[i+1].a) r = i;
    if(e[i].a != e[i-1].a) solve(i, r);
    }
    hs[m+1] = 0;
    for(int i = 1; i <= m; i++) c[i] = e[i].a;
    }
    inline int query(int u, int p){
    int pos = upper_bound(c + 1, c + m + 1, p) - c;
    int rt = Dsu::ask(hs[pos], u); return -fa.get(hs[pos], rt);
    }

    inline void cleartype(){
    #define mem(x) memset(x, 0, sizeof(x))
    fa.clear(), sz.clear();
    mem(a), mem(b), mem(nxt), mem(head), cnt = 0;
    }
    inline void init(){
    read(n), read(m);
    for(int i = 1, x, y, z, a; i <= m; i++){
    read(x), read(y), read(z), read(a);
    add(x, y, z), add(y, x, z), e[i] = (Edge){x, y, a};
    }
    read(Q), read(K), read(S);
    }
    inline void realmain(){
    cleartype(), init(), dijkstra(), BuildDsu();
    int lastans = 0;
    while(Q--){
    int u, p; read(u), read(p);
    p = (p + K * lastans) % (S + 1);
    u = (u + K * lastans - 1) % n + 1;
    printf("%d ", lastans = query(u, p));
    }
    }
    int main(){
    int T; read(T); while(T--) realmain();
    return 0;
    }

  • 相关阅读:
    【MySQL案件】mysql登录-S失败
    python3使用smtplib发电子邮件
    oracle创建user具体指示
    设计模式的饕餮盛宴
    iOS使用UIScrollView实现左右滑动UITableView和UICollectionView
    MIFARE系列6《射频卡与读写器的通信》
    hdu1286 寻找新朋友 (欧拉功能)
    Python开发环境的搭建(win7)
    2014年度辛星完全解读html部分
    S2SH新手框架建立具体过程
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9351571.html
Copyright © 2011-2022 走看看