[NOI2018] 归程 Solution
闲话
实在懒得写了。
Kruskal 重构树的思想理解难度过高,不如可持久化并查集,思路直接,代码好写,往机位上一坐,双手放在键盘上,直接不看键盘打,半个小时就写完了,还压根不需要调试。
如果要调试,只可能是数组开小了或者 memset 初始位置写错了。
代码
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <functional>
#include <queue>
#include <utility>
#include <vector>
using namespace std;
const int N = 2e5 + 10, M = 4e5 + 10;
template <typename _Tp> inline void read(_Tp &x)
{
char ch;
while (ch = getchar(), !isdigit(ch) and ~ch)
;
x = (ch ^ 48);
while (ch = getchar(), isdigit(ch))
x = (x << 3) + (x << 1) + (ch ^ 48);
}
template <typename _Tp, typename... _Args> inline void read(_Tp &x, _Args &...args)
{
read(x);
read(args...);
}
template <typename _Tp> inline void print(_Tp x)
{
if (x > 9)
print(x / 10);
putchar((x % 10) ^ 48);
}
template <typename _Tp, typename... _Args> inline void print(_Tp x, _Args... args)
{
print(x);
putchar(' ');
print(args...);
}
int n, m, idx1, idx2, rt[M];
using ll = long long;
ll dis[N];
bool vis[N];
using pli = pair<ll, int>;
using pii = pair<int, int>;
vector<pii> road[N];
struct node
{
int ls, rs;
} tr[N << 6];
struct node2
{
int fa, siz;
ll res;
} trs[N << 2];
struct edge
{
int x, y, l, a;
bool operator<(const edge &ele) const
{
if (a != ele.a)
return a > ele.a;
if (l != ele.a)
return l < ele.l;
if (x != ele.x)
return x < ele.x;
return y < ele.y;
}
} path[M];
priority_queue<pli, vector<pli>, greater<>> q;
void build(int &x, int l, int r)
{
x = ++idx1;
if (l == r)
{
tr[x].ls = ++idx2;
trs[idx2] = {l, 1, dis[l]};
return;
}
int mid = (l + r) >> 1;
build(tr[x].ls, l, mid);
build(tr[x].rs, mid + 1, r);
}
node2 query(int &x, int l, int r, int tar)
{
if (l == r)
return trs[tr[x].ls];
int mid = (l + r) >> 1;
if (tar <= mid)
return query(tr[x].ls, l, mid, tar);
return query(tr[x].rs, mid + 1, r, tar);
}
node2 buf;
void update(int &x, int l, int r, int tar)
{
tr[++idx1] = tr[x];
x = idx1;
if (l == r)
{
tr[x].ls = ++idx2;
trs[idx2] = buf;
return;
}
int mid = (l + r) >> 1;
if (tar <= mid)
return update(tr[x].ls, l, mid, tar);
return update(tr[x].rs, mid + 1, r, tar);
}
node2 find(int k, int x)
{
int tmpr = 0;
node2 tmp = query(rt[k], 1, n, x);
while (tmp.fa != x)
{
x = tmp.fa;
tmp = query(rt[k], 1, n, x);
tmpr++;
}
return tmp;
}
void merge(int k, int x, int y)
{
node2 tx = find(k, x), ty = find(k, y);
if (tx.fa == ty.fa)
return;
if (tx.siz > ty.siz)
{
buf = ty;
buf.fa = tx.fa;
update(rt[k], 1, n, ty.fa);
buf = {tx.fa, tx.siz + ty.siz, min(tx.res, ty.res)};
update(rt[k], 1, n, tx.fa);
}
else
{
buf = tx;
buf.fa = ty.fa;
update(rt[k], 1, n, tx.fa);
buf = {ty.fa, tx.siz + ty.siz, min(tx.res, ty.res)};
update(rt[k], 1, n, ty.fa);
}
}
int qr, k, s;
void init_global()
{
}
void init_local()
{
read(n, m);
idx1 = idx2 = 0;
for (int i = 1; i <= n; i++)
road[i].clear();
for (int i = 1, x, y, l, a; i <= m; i++)
{
read(x, y, l, a);
path[i] = {x, y, l, a};
road[x].emplace_back(y, l);
road[y].emplace_back(x, l);
}
}
void run()
{
memset(vis + 1, 0, n);
memset(dis + 1, 0x3f, n << 3);
q.emplace(0, 1);
dis[1] = 0;
while (q.size())
{
auto [cv, tx] = q.top();
q.pop();
if (vis[tx])
continue;
vis[tx] = true;
for (auto &[i, v] : road[tx])
{
if (dis[i] <= cv + v or vis[i])
continue;
dis[i] = cv + v;
q.emplace(cv + v, i);
}
}
rt[0] = 0;
build(rt[0], 1, n);
sort(path + 1, path + m + 1);
for (int i = 1; i <= m; i++)
{
rt[i] = rt[i - 1];
merge(i, path[i].x, path[i].y);
}
read(qr, k, s);
for (int i = 1, v, p, la = 0, tp; i <= qr; i++)
{
read(v, p);
v = (v + k * la - 1) % n + 1;
p = (p + k * la) % (s + 1);
tp = lower_bound(path + 1, path + m + 1, edge{0, 0, 0, p}) - path - 1;
la = find(tp, v).res;
print(la);
putchar('\n');
}
}
int main()
{
// freopen("return.in", "r", stdin);
// freopen("return.out", "w", stdout);
int T = 1;
scanf("%d", &T);
init_global();
while (T--)
{
init_local();
run();
}
}