想看克鲁斯卡尔重构树戳我
又学了一个解法暴力艹过了此题
所以常数还是一个很重要的东西啦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;
}