[NOI2018 归程] 可持久化并查集 Dijkstra

想看克鲁斯卡尔重构树戳我
又学了一个解法暴力艹过了此题
所以常数还是一个很重要的东西啦2333
对于这个题可以使用可持久化并查集维护每个联通块中离一号点最近的距离
只要对于加边的海拔倒序可持久化就可以了 具体实现 见代码应该很好懂
时间复杂度 O(nlogm+mlogn+qlog2n) O ( n l o g m + m l o g n + q l o g 2 n )
有一个东西自己想了会
就是为什么更新联通块深度的时候不用新开点但是更新联通块答案的时候要
首先对于当前这个版本更新深度的时候 只会对当前这个版本造成影响 那么就不用新开点
但是更新联通块答案的时候 指针可能会指回之前的版本 如果直接修改的话就影响了之前的版本
所以必须要新开节点来记录这个变化
update:更新深度的时候已经新开过一个版本于是就不用加点了ovo
题目链接

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define FOR(i, a, b) for(register int i = a; i >= b; -- i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define PLI pair<ll, int>
#define mp make_pair

using namespace std;
typedef long long ll;

const int maxn = 2e5 + 10, maxm = 4e5 + 10;
int to[maxm << 1], head[maxn], nxt[maxm << 1], a[maxm << 1], l[maxm << 1], e;
int n, m, T, tmp[maxm], root[maxm], num, now, Q, K, S;
ll dis[maxn], lastans;

struct edge
{
    int x, y, L, A;
}E[maxn << 2];

template<class T>inline bool chkmin(T &_, T __)
{
    return _ > __ ? _ = __, 1 : 0;
}

bool cmp(edge X, edge Y)
{
    return X.A < Y.A;
}

inline int read()
{
    int _ = 0, ___ = 1, __ = getchar();
    for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
    for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return _ * ___;
}

void add(int x, int y, int L, int A)
{
    to[++ e] = y;
    nxt[e] = head[x];
    head[x] = e;
    l[e] = L;
    a[e] = A;
}

void Dijkstra()
{
    priority_queue<PLI, vector<PLI>, greater<PLI> >q;
    For(i, 1, n)
        dis[i] = 1e18;
    q.push(mp(dis[1] = 0, 1));
    while(!q.empty())
    {
        PLI k = q.top(); q.pop();
        if(k.first > dis[k.second])
            continue;
        go(k.second, i)
            if(chkmin(dis[to[i]], dis[k.second] + l[i]))
                q.push(mp(dis[to[i]], to[i]));
    }
}

namespace Chairman_Tree
{
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
    int cnt;
    struct node
    {
        int ch[2], fa, height;
        ll ans;
    }T[maxm * 40];
    void build(int &x, int l, int r)
    {
        x = ++ cnt;
        if(l == r)
            T[x].fa = l, T[x].ans = dis[l];
        else
        {
            build(ls(x), l, mid);
            build(rs(x), mid + 1, r);
        }
    }
    int query(int x, int l, int r, int p)
    {
        if(l == r)
            return x;
        if(p <= mid)
            return query(ls(x), l, mid, p);
        return query(rs(x), mid + 1, r, p);
    }
    void update(int &x, int pre, int l, int r, int p, int dad)
    {
        T[x = ++ cnt] = T[pre];
        if(l == r)
            T[x].fa = dad;
        else
        {
            if(p <= mid)
                update(ls(x), ls(pre), l, mid, p, dad);
            else
                update(rs(x), rs(pre), mid + 1, r, p, dad);
        }
    }
    void updateans(int &x, int pre, int l, int r, int p, ll res)
    {
        T[x = ++ cnt] = T[pre];
        if(l == r)
            T[x].ans = res;
        else
        {
            if(p <= mid)
                updateans(ls(x), ls(pre), l, mid, p, res);
            else
                updateans(rs(x), rs(pre), mid + 1, r, p, res);
        }
    }
    void add(int x, int l, int r, int p)
    {
        if(l == r)
            ++ T[x].height;
        else
        {
            if(p <= mid)
                add(ls(x), l, mid, p);
            else
                add(rs(x), mid + 1, r, p);
        }
    }
    int find(int rt, int x)
    {
        int now = query(rt, 1, n, x);
        while(T[now].fa != x)
        {
            x = T[now].fa;
            now = query(rt, 1, n, x);
        }
        return now;
    }
}   

int main()
{
#ifndef ONLINE_JUDGE
    freopen("4768.in", "r", stdin);
    freopen("4768.out", "w", stdout);
#endif
    int x, y;   
    for(T = read(); T -- ; )
    {
        For(i, 1, n) head[i] = 0;
        n = read(), now = m = read();
        Chairman_Tree::cnt = lastans = e = 0;
        For(i, 1, m)
        {
            E[i] = (edge){read(), read(), read(), read()};
            add(E[i].x, E[i].y, E[i].L, E[i].A);
            add(E[i].y, E[i].x, E[i].L, E[i].A);
            tmp[i] = E[i].A;    
        }
        Dijkstra();
        sort(tmp + 1, tmp + m + 1); 
        sort(E + 1, E + m + 1, cmp);
        num = unique(tmp + 1, tmp + m + 1) - tmp - 1;
        Chairman_Tree::build(root[num + 1], 1, n);      
        FOR(i, num, 1)  
        {
            root[i] = root[i + 1];
            while(tmp[i] == E[now].A)
            {
                int u = Chairman_Tree::find(root[i], E[now].x), v = Chairman_Tree::find(root[i], E[now].y);
                if(Chairman_Tree::T[u].fa != Chairman_Tree::T[v].fa)
                {
                    if(Chairman_Tree::T[u].height > Chairman_Tree::T[v].height)
                        swap(u, v);
                    Chairman_Tree::update(root[i], root[i], 1, n, Chairman_Tree::T[u].fa, Chairman_Tree::T[v].fa);
                    if(Chairman_Tree::T[u].ans < Chairman_Tree::T[v].ans)
                        Chairman_Tree::updateans(root[i], root[i], 1, n, Chairman_Tree::T[v].fa, Chairman_Tree::T[u].ans);
                    if(Chairman_Tree::T[u].height == Chairman_Tree::T[v].height)
                        Chairman_Tree::add(root[i], 1, n, Chairman_Tree::T[v].fa);
                }
                -- now;
            }
        }
        Q = read(), K = read(), S = read();
        while(Q --)
        {
            x = read(), y = read();
            x = (lastans * K + x - 1) % n + 1;
            y = (lastans * K + y) % (S + 1);
            y = upper_bound(tmp + 1, tmp + num + 1, y) - tmp;
            printf("%lld\n", lastans = Chairman_Tree::T[Chairman_Tree::find(root[y], x)].ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值