[CF1192B]Dynamic Diameter
题目
题解
题目交代了是“动态直径”,肯定是在线啦,问题在于我们选用什么数据结构维护,以及怎么维护.
比较经典地,对于每个数标上 \(\tt dfn\),然后使用线段树维护。问题是在线段树上如何维护一个区间的点的直径?对于一颗线段树上的区间,它的直径的两个端点必然来源于它的子区间的两条直径的端点,我们只需要用四次枚举每种情况即可.
考虑修改的时候怎么维护线段树,首先,对于一条边 \(e\) 被修改,假设它连接的深度较深的点为 \(u\),那么,在 \(u\) 的子树中的直径没有受到影响,唯一有影响的是跨越了 \(u\) 的点的直径,在线段树上来说,就是包含了 dfn[u]
以及 dfn[u]+sz[u]-1
两个端点的区间需要重新计算,一次修改的计算是 \(\mathcal O(\log^2n)\),总复杂度 \(\mathcal O(n\log^2n)\).
代码中对于单点的深度使用的是 BIT
利用差分维护的.
代码
# include <cstdio>
# include <algorithm>
using namespace std;
namespace Elaina{
# define rep(i,l,r) for(int i=l, i##_end_ = r; i <= i##_end_; ++ i)
# define fep(i,l,r) for(int i=l, i##_end_ = r; i >= i##_end_; -- i)
# define fi first
# define se second
# define Endl putchar('\n')
# define writc(x, c) fwrit(x), putchar(c)
// # define int long long
typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
typedef unsigned int uint;
template<class T>inline T Max(const T x, const T y){return x < y ? y : x;}
template<class T>inline T Min(const T x, const T y){return x < y ? x : y;}
template<class T>inline T fab(const T x){return x < 0 ? -x : x;}
template<class T>inline void getMax(T& x, const T y){x = Max(x, y);}
template<class T>inline void getMin(T& x, const T y){x = Min(x, y);}
template<class T>T gcd(const T x, const T y){return y ? gcd(y, x % y) : x;}
template<class T>inline T readin(T x){
x=0; int f = 0; char c;
while((c = getchar()) < '0' || '9' < c) if(c == '-') f = 1;
for(x = (c ^ 48); '0' <= (c = getchar()) && c <= '9'; x = (x << 1) + (x << 3) + (c ^ 48));
return f ? -x : x;
}
template<class T>void fwrit(const T x){
if(x < 0)return putchar('-'), fwrit(-x);
if(x > 9)fwrit(x / 10); putchar(x % 10 ^ 48);
}
}
using namespace Elaina;
const int maxn = 1e5;
const ll inf = (1ll << 50);
int n, q; ll w;
struct edge{int to, nxt; ll w;
edge(const int T = 0, const int N = 0, const ll W = 0) : to(T), nxt(N), w(W){}
}e[maxn * 2 + 5];
int ecnt = 1;// pay attention!
int tail[maxn + 5];
inline void add_edge(const int u, const int v, const ll w){
e[++ ecnt] = edge(v, tail[u], w); tail[u] = ecnt;
e[++ ecnt] = edge(u, tail[v], w); tail[v] = ecnt;
}
inline void init(){
n = readin(1), q = readin(1); w = readin(1ll);
int a, b; ll c;
rep(i, 1, n - 1){
a = readin(1), b = readin(1), c = readin(1ll);
add_edge(a, b, c);
}
}
ll dis[maxn + 5];
int sz[maxn + 5], wson[maxn + 5], dep[maxn + 5], fa[maxn + 5];
void dfs1(const int u, const int par){
sz[u] = 1, dep[u] = dep[par] + 1, fa[u] = par;
for(int i = tail[u], v; i; i = e[i].nxt)
if((v = e[i].to) != par){
dis[v] = dis[u] + e[i].w;
dfs1(v, u), sz[u] += sz[v];
if(sz[v] > sz[wson[u]]) wson[u] = v;
}
}
int c[maxn + 5], dfn[maxn + 5], tp[maxn + 5], times;
void dfs2(const int u, const int par){
c[dfn[u] = ++ times] = u;
if(!wson[u]) return;
tp[wson[u]] = tp[u], dfs2(wson[u], u);
for(int i = tail[u], v; i; i = e[i].nxt)
if((v = e[i].to) != par && v != wson[u])
dfs2(tp[v] = v, u);
}
inline int findlca(int u, int v){
while(tp[u] != tp[v]){
// printf("Now u == %d, v == %d\n", u, v);
if(dep[tp[u]] < dep[tp[v]]) swap(u, v);
u = fa[tp[u]];
}
return dep[u] < dep[v] ? u : v;
}
inline int lowbit(const int i){return i & (-i);}
/** @brief maintain the distance of the nodes*/
struct BIT{
ll c[maxn + 5];
inline void modify(int i, const ll x){
for(; i <= n; i += lowbit(i))
c[i] += x;
}
inline void modify(const int l, const int r, const ll x){
modify(l, x), modify(r + 1, -x);
}
inline ll query(int i){
ll ret = 0;
for(; i > 0; i -= lowbit(i)) ret += c[i];
return ret;
}
}bit;
inline ll query_dis(const int u, const int v){
// printf("query_dis :> u == %d, v == %d\n", u, v);
if(u == 0 || v == 0) return -inf;
int lca = findlca(u, v);
return bit.query(dfn[u]) + bit.query(dfn[v]) - 2 * bit.query(dfn[lca]);
}
struct diameter{
int c[2]; ll d;
inline diameter operator &(const diameter rhs) const{
diameter ret;
if(d < rhs.d) ret = rhs;
else ret = (*this);
rep(i, 0, 1) rep(j, 0, 1){
int x = c[i], y = rhs.c[j];
ll dis;
if((dis = query_dis(x, y)) > ret.d){
ret.d = dis;
ret.c[0] = x, ret.c[1] = y;
}
}
return ret;
}
};
/** @brief maintain the particular interval's diameter*/
diameter tre[maxn << 2 | 2];
# define ls (i << 1)
# define rs (i << 1 | 1)
# define mid ((l + r) >> 1)
# define _lq ls, l, mid
# define _rq rs, mid + 1, r
inline void pushup(const int i){
tre[i] = tre[ls] & tre[rs];
}
void Build(const int i = 1, const int l = 1, const int r = n){
if(l == r){
tre[i].c[0] = c[l];
tre[i].d = -inf;
return;
}
Build(_lq), Build(_rq);
pushup(i);
}
void Modify(const int L, const int R, const int i = 1, const int l = 1, const int r = n){
if(L <= l && r <= R) return;
if(L <= mid) Modify(L, R, _lq);
if(mid < R) Modify(L, R, _rq);
pushup(i);
}
void print(const int i = 1, const int l = 1, const int r = n){
if(l != r) print(_lq), print(_rq);
printf("tre[%d] :> l == %d, r == %d, (%d, %d, %lld)\n", i, l, r, tre[i].c[0], tre[i].c[1], tre[i].d);
}
signed main(){
init();
dfs1(1, 0);
// puts("finished 1!");
dfs2(tp[1] = 1, 0);
// puts("finished 2!");
rep(i, 1, n){
// 注意此处传的下标
bit.modify(i, dis[c[i]] - dis[c[i - 1]]);
// printf("bit[%d].insert %lld\n", i, dis[c[dfn[i]]] - dis[c[dfn[i - 1]]]);
}
// puts("finished 3!");
// rep(i, 1, n){
// printf("node %d :> sz == %d, wson == %d, fa == %d, dep == %d, dis == %lld, tp == %d, dfn == %d\n", i, sz[i], wson[i], fa[i], dep[i], dis[i], tp[i], dfn[i]);
// }
// rep(i, 1, n) printf("dis %d == %lld\n", i, bit.query(dfn[i]));
Build();
// printf("ans 1 == %lld\n", tre[1].d);
// print();
// rep(i, 1, n) printf("dis %d == %lld\n", i, bit.query(i));
ll las = 0, E; int D;
while(q --){
D = (0ll + readin(1) + las) % (n - 1) + 1;
E = (readin(1ll) + las) % w;
D <<= 1;
int u = e[D].to;
if(dep[u] < dep[e[D ^ 1].to])
u = e[D ^ 1].to;
// printf("update u == %d\n", u);
ll delta = E - e[D].w;
e[D].w = e[D ^ 1].w = E;
// printf("delta == %lld\n", delta);
bit.modify(dfn[u], dfn[u] + sz[u] - 1, delta);
Modify(dfn[u], dfn[u] + sz[u] - 1);
writc(las = tre[1].d, '\n');
// rep(i, 1, n) printf("dis %d == %lld\n", i, bit.query(dfn[i]));
// print();
}
return 0;
}