P6845 [CEOI 2019] Dynamic Diameter
P6845 [CEOI 2019] Dynamic Diameter
题目描述
有一棵树,含 \(n\) 个节点,边带权。
会有 \(q\) 次修改,每次会将树上的一条边的边权进行修改,在每次修改后,您需要求出每次修改后,这棵树的直径上的边权和。
本题强制在线。
输入格式
第一行为三个整数 \(n,q,w\),分别表示点的个数,询问的个数和边权的上限。
接下来 \(n-1\) 行,每一行为三个整数 \(a_i,b_i,c_i\),表示 \(a_i\) 到 \(b_i\) 有一条边权为 \(c_i\) 的边。
接下来 \(q\) 行,每行两个经过加密的整数 \(d_j,e_j\)。
解密方式如下:
- \(d_j'=(d_j+\text{last})\bmod(n-1)\)
- \(e_j'=(e_j+\text{last})\bmod w\)
其中 \(\text{last}\) 表示上一个询问的答案,初值为 \(0\)。
表示将第 \(d_j'+1\) 条边的边权改为 \(e_j'\)。
输出格式
共输出 \(q\) 行,一行一个整数,第 \(i\) 行的整数表示在第 \(i\) 次修改后的直径上的权值总和。
数据范围
对于 \(100\%\) 的数据,保证 \(2\le n\le 10^5\),\(1\le q\le 10^5\),\(1\le w\le 2\times 10^{13}\),\(1\le a_i,b_i\le n\),\(0\le c_i,e_j<w\),\(0\le d_j<n-1\)。
说明
本题译自 Central-European Olympiad in Informatics 2019 Day 1 T2 Dynamic Diameter。
Solution:
感觉有点神的树上差分题,首先主播不会 ddp 也不想用 ddp。
首先我们知道 $ dis_{(x,y)} = dep_x + dep_y-2\times dep_{lca(x,y)} $
然后如果我们将树拍出一个 欧拉序 的话我们会发现:在欧拉序上的任意一个以 \(x \ ,\ y\) 为两端点的区间内, \(lca(x,y)\) 一定是其中深度最小的那个。
有了这个性质我们就能很好地维护树的直径了,我们用一颗线段树维护以下值:
然后是转移方程:
然后我们会发现:\(lp,rp\) 式子中的 \(j\) 实际上就是 \(lca\) 可能的位置。那么我们在合并两个区间 \({ls,rs}\) 时,如果当前区间新答案的 lca 落在 \(ls\) 内,那么它会在 \(lp_{ls}\ + \ mx_{rs}\) 中取到,反之则会在 \(rp_{ls}\ +\ mx_{ls}\) 中取到。
然后注意一下,本题我们取的序列是 欧拉序 而非 dfs序 应为上述性质只在 欧拉序 上生效。
Code:
#include<bits/stdc++.h>
#define int long long
const int N=2e5+5;
using namespace std;
int n,m,cnt,W;
vector<tuple<int,int>> E[N];
int q[N],st[N],ed[N],u[N],v[N],w[N],dis[N];
void dfs(int x,int fa)
{
q[st[x]=++cnt]=x;
for(auto [to,id] : E[x])
{
if(to==fa)continue;
u[id]=x;
v[id]=to;
dis[to]=dis[x]+w[id];
dfs(to,x);
q[++cnt]=x;
}
ed[x]=cnt;
}
//Segment_Tree
#define ls x<<1
#define rs x<<1|1
struct Tree
{
int ans,mx,mi,lp,rp,tag;
inline void push(int val)
{
mx+=val;
mi+=val;
lp-=val;
rp-=val;
tag+=val;
}
}t[N<<2];
inline void push_up(int x)
{
t[x].mx=max(t[ls].mx,t[rs].mx);
t[x].mi=min(t[ls].mi,t[rs].mi);
t[x].lp=max(max(t[ls].lp,t[rs].lp),t[ls].mx-2*t[rs].mi);
t[x].rp=max(max(t[ls].rp,t[rs].rp),t[rs].mx-2*t[ls].mi);
t[x].ans=max(max(t[ls].ans,t[rs].ans),max(t[ls].lp+t[rs].mx,t[ls].mx+t[rs].rp));
return;
}
inline void push_down(int x)
{
if(!t[x].tag)return;
int tag=t[x].tag;t[x].tag=0;
t[ls].push(tag);t[rs].push(tag);
return;
}
void build(int x,int l,int r)
{
if(l==r)
{
t[x].mi=t[x].mx= dis[q[l]];
t[x].lp=t[x].rp=-dis[q[l]];
t[x].ans=0;
return;
}
int mid = l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
push_up(x);
}
void upd(int x,int l,int r,int L,int R,int val)
{
if(L<=l&&r<=R)
{
t[x].push(val);
return;
}
int mid=l+r>>1;
push_down(x);
if(L<=mid) upd(ls,l,mid,L,R,val);
if(mid<R)upd(rs,mid+1,r,L,R,val);
push_up(x);
}
void work()
{
cin>>n>>m>>W;
cnt=0;
for(int i=1,x,y,z;i<n;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
E[x].emplace_back(y,i);
E[y].emplace_back(x,i);
w[i]=z;
}
dfs(1,0);
int inf=n*2-1;
build(1,1,inf);
int ans=0;
for(int i=1,id,val;i<=m;i++)
{
scanf("%lld%lld",&id,&val);
id=(id+ans)%(n-1)+1;
val=(val+ans)%W;
upd(1,1,inf,st[v[id]],ed[v[id]],val-w[id]);
ans=t[1].ans;
w[id]=val;
printf("%lld\n",ans);
}
}
#undef int
int main()
{
//freopen("Dynamic Diameter.in","r",stdin);
//freopen("Dynamic Diameter.out","w",stdout);
work();
return 0;
}

浙公网安备 33010602011771号