#欧拉序,线段树#洛谷 6845 [CEOI2019] Dynamic Diameter
题目
动态修改边权,强制在线询问树的直径。
分析
设 \(dis[x]\) 表示 \(x\) 到1号点的距离。
那么树的直径就可以表示成 \(dis[x]+dis[y]-2*dis[lca]\)
只需要保证 \(lca\) 被夹在 \(x,y\) 之间,欧拉序可以满足这样的条件。
用欧拉序将树拍成一个序列,也就是要询问 \(\max_{i\leq j\leq k}\{dis[i]+dis[k]-2*dis[j]\}\)
维护区间最大值,区间最小值,\(dis[i]-2*dis[j]\) 的最大值,\(dis[k]-2*dis[j]\) 的最大值,以及区间的答案。
修改边权相当于在子树区间加,直接用线段树维护就可以了。
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=200011; typedef long long lll;
struct node{int y; lll w; int next;}e[N];
int dfn[N],nfd[N],as[N],n,et=1,m,tot,rfn[N];
lll lim,lans,dis[N],w[N<<2],lazy[N<<2],lmx[N<<2],rmx[N<<2],mx[N<<2],mn[N<<2];
lll iut(){
lll ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
lll min(lll a,lll b){return a<b?a:b;}
lll max(lll a,lll b){return a>b?a:b;}
void dfs(int x,int fa){
nfd[dfn[x]=++tot]=x;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
dis[e[i].y]=dis[x]+e[i].w,
dfs(e[i].y,x),nfd[++tot]=x;
}
rfn[x]=tot;
}
void pup(int k){
mn[k]=min(mn[k<<1],mn[k<<1|1]),mx[k]=max(mx[k<<1],mx[k<<1|1]);
lmx[k]=max(max(lmx[k<<1],lmx[k<<1|1]),mx[k<<1]-2*mn[k<<1|1]);
rmx[k]=max(max(rmx[k<<1],rmx[k<<1|1]),mx[k<<1|1]-2*mn[k<<1]);
w[k]=max(max(w[k<<1],w[k<<1|1]),max(lmx[k<<1]+mx[k<<1|1],mx[k<<1]+rmx[k<<1|1]));
}
void build(int k,int l,int r){
if (l==r){
mn[k]=mx[k]=dis[nfd[l]],
lmx[k]=rmx[k]=-dis[nfd[l]];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pup(k);
}
void ptag(int k,lll z){mn[k]+=z,mx[k]+=z,lmx[k]-=z,rmx[k]-=z,lazy[k]+=z;}
void update(int k,int l,int r,int x,int y,lll z){
if (l==x&&r==y){
ptag(k,z);
return;
}
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
pup(k);
}
int main(){
n=iut(),m=iut(),lim=iut();
for (int i=1;i<n;++i){
int x=iut(),y=iut(); lll w=iut();
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
dfs(1,0),build(1,1,tot);
for (int i=1;i<=m;++i){
int o=(iut()+lans)%(n-1)+1; lll W=(iut()+lans)%lim;
int x=e[o<<1].y,y=e[o<<1|1].y;
if (dis[x]<dis[y]) x^=y,y^=x,x^=y;
update(1,1,tot,dfn[x],rfn[x],W-e[o<<1].w);
e[o<<1].w=e[o<<1|1].w=W,print(lans=w[1]),putchar(10);
}
return 0;
}