上海网络赛A前置技能题。
大致题意
给定一颗树,树边有边权,每次修改一条边的边权,要求输出当前树的直径的长度,强制在线。
思路
https://www.cnblogs.com/TinyWong/p/11260601.html
上海网络赛A的题解推荐的巨巨博客,写了三种方法搞这个题。
- 树链剖分+lca nlog2n splay+lca nlogn
- 动态dp nlogn
- 全dfs序 nlogn
由于蒟蒻前两个不会…只能学一下第三种。全dfs序是一个类似欧拉序的东西,可以理解为完全描述了dfs搜索的路径,普通的dfs序没有描述回溯的时间戳,而全dfs序的回溯路径也会被记录,所以总共有n个节点加n-1条回溯边,所以总共有2*n-1个时间戳。修改边的操作还是把边权搞成点权,思路同POJ2763。用线段树维护时间戳序列,任意两个时间戳之间代表了一段树上的移动路径。
每一段路径维护这样几个信息:
- val 表示这段路径上距离根最远的距离 max_dis[x]
- M 表示这段路径上距离根最近的距离 min_dis[x] ,作为lca,方便计算记录其为 -2dis[x]。
- LM 表示选择左端点以及lca的最长距离。
- MR 表示选择右端点以及lca的最长距离。
- LMR 表示选择左lca右 也就是完整的一条链的最长长度。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define maxm 1000006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
#define PI acos(-1)
#define ls x<<1
#define rs x<<1|1
ll read(){
ll x=0,f=1ll;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,m;ll W;
struct edge{int u,v;ll w;int nxt;}ed[maxn<<1];
int head[maxn],tot;
void add(int x,int y,ll z){ed[++tot]={x,y,z,head[x]};head[x]=tot; }
int id[maxn<<1],in[maxn],out[maxn],cnt,dep[maxn];
ll dis[maxn];
void dfs(int x,int y){
dep[x]=dep[y]+1;
id[in[x]=++cnt]=x;
for(int i=head[x];i;i=ed[i].nxt){
int v=ed[i].v;
if(v==y)continue;
dis[v]=dis[x]+ed[i].w;
dfs(v,x);
id[++cnt]=x;
}
out[x]=cnt;
}
struct node{ll val,M,LM,MR,LMR,laz;}t[maxn<<2];
void pushdown(int x){
t[ls].laz+=t[x].laz;t[rs].laz+=t[x].laz;
t[ls].val+=t[x].laz;t[rs].val+=t[x].laz;
t[ls].M-=2*t[x].laz;t[rs].M-=2*t[x].laz;
t[ls].LM-=t[x].laz;t[rs].LM-=t[x].laz;
t[ls].MR-=t[x].laz;t[rs].MR-=t[x].laz;
t[x].laz=0;
}
void pushup(int x){
t[x].val=max(t[ls].val,t[rs].val);
t[x].M=max(t[ls].M,t[rs].M);
t[x].LM=max(max(t[ls].LM,t[rs].LM),t[ls].val+t[rs].M);
t[x].MR=max(max(t[ls].MR,t[rs].MR),t[ls].M+t[rs].val);
t[x].LMR=max(max(t[ls].LMR,t[rs].LMR),max(t[ls].val+t[rs].MR,t[ls].LM+t[rs].val));
}
void build(int x,int l,int r){
if(l==r){
ll d=dis[id[l]];
t[x].val=d;
t[x].M=-2*d;
t[x].LM=t[x].MR=-d;
t[x].LMR=t[x].laz=0;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(x);
}
void update(int x,int l,int r,int lp,int rp,int s){
if(l<r&&t[x].laz)pushdown(x);
if(lp<=l&&r<=rp){
t[x].laz+=s;
t[x].val+=s;
t[x].LM-=s;t[x].MR-=s;
t[x].M-=2*s;
return ;
}
int mid=(l+r)>>1;
if(lp<=mid)update(ls,l,mid,lp,rp,s);
if(mid+1<=rp)update(rs,mid+1,r,lp,rp,s);
pushup(x);
}
int main()
{
n=read();m=read();W=read();
int x,y;ll z;
inc(i,1,n-1){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
dfs(1,0);
build(1,1,cnt);
ll ans=0;
while(m--){
x=((read()+ans)%(n-1))+1;z=(read()+ans)%W;
int u=ed[2*x-1].u;
int v=ed[2*x-1].v;
int xx=(dep[u]<dep[v])?v:u;
update(1,1,cnt,in[xx],out[xx],z-ed[2*x-1].w);
ed[2*x-1].w=z;
printf("%lld\n",ans=t[1].LMR);
}
return 0;
}