当前位置: 首页 > 工具软件 > Diameter > 使用案例 >

CF1192B Dynamic Diameter(LCT)

钱旻
2023-12-01

Foreword \text{Foreword} Foreword

@zhengrunzhe 大佬的矩阵做法过于神奇,蒟蒻无法理解…
欧拉序的做法确实非常巧妙,但我也想不到这么神仙的做法…
提供一种可能简单一些的 LCT 做法。
由于本人 LCT 无法像大佬那么神,讲的会比较详细一些,也许对其他 LCT 平民玩家更加友好?

Solution \text{Solution} Solution

本题有一个很关键的性质:边权非负。(欧拉序的做法也要基于这个性质)
又发现修改无非改大/小,在/不在原直径上,利用非负的性质分别讨论一下,就会发现新直径至少有一个节点和原来相同
所以我们一开始暴力求出直径后,只需要不断把原直径的两端点提出来,用从二者出发新的最长路径来尝试作为新直径就行了。
所以现在只需要动态维护从一个点出发的最长路径

常规套路,先边化点,边权化点权。
w x w_x wx 表示 x x x 的点权, s u m x sum_x sumx 表示 x x x splay子树内点权之和, d i s x dis_x disx 表示从 x x x 所在 splay 子树内深度最浅的节点出发往子树延伸的最长路径。
先不考虑 x x x 实链父亲,尝试求出 x x x 出发往子树延伸的最长路径 r e s x res_x resx

一开始有:
r e s x = w x res_x=w_x resx=wx
对于 x x x 的虚儿子,对每个节点开一个 std::set 维护虚子树,进行转移:
r e s x ← max ⁡ s o n d i s s o n + w x res_x\gets \max_{son}dis_{son}+w_x resxsonmaxdisson+wx
还有从 x x x 的实儿子转移,不难发现其对应的就是 d i s r s x dis_{rs_x} disrsx
r e s x ← d i s r s x + w x res_x\gets dis_{rs_x}+w_x resxdisrsx+wx
求完 r e s x res_x resx 后,如果 x x x 没有左儿子,说明他就是链头,直接让 d i s x = r e s x dis_x=res_x disx=resx 即可;否则,链头可以不使用 r e s x res_x resx 的转移,或者使用 r e s x res_x resx 的转移,那么还要加上 x x x 到链头一段的权值和,分别对应 max 的前后两项:
d i s x = max ⁡ ( d i s l s x , r e s x + s u m l s x ) dis_x=\max(dis_{ls_x},res_x+sum_{ls_x}) disx=max(dislsx,resx+sumlsx)

这样就做完了。由于转移不对称,所以我们还要镜像的处理一个 d i s ′ x dis'x disx,在翻转时直接交换两项即可。

Code \text{Code} Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;

const int N=2e5+100;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

int n,m;


#define pr pair<ll,int>
#define mkp make_pair
pr operator + (const pr &o,const ll &w){return mkp(o.first+w,o.second);}

int tr[N][2],rev[N],f[N];
ll sum[N],w[N];
pr dis1[N],dis2[N];
multiset<pr>s[N];
#define ls(x) tr[x][0]
#define rs(x) tr[x][1]
inline bool nroot(int x){return ls(f[x])==x||rs(f[x])==x;}
inline bool which(int x){return rs(f[x])==x;}

inline void pushup(int x){
  sum[x]=w[x]+sum[ls(x)]+sum[rs(x)];
  
  dis1[x]=s[x].empty()?mkp(w[x],x<=n?x:-1):(*s[x].rbegin())+w[x];
  if(rs(x)) dis1[x]=max(dis1[x],dis1[rs(x)]+w[x]);
  if(ls(x)) dis1[x]=max(dis1[ls(x)],dis1[x]+sum[ls(x)]);
  
  dis2[x]=s[x].empty()?mkp(w[x],x<=n?x:-1):(*s[x].rbegin())+w[x];
  if(ls(x)) dis2[x]=max(dis2[x],dis2[ls(x)]+w[x]);
  if(rs(x)) dis2[x]=max(dis2[rs(x)],dis2[x]+sum[rs(x)]);
  
  return;
}
inline void Rev(int x){
  if(x){
    rev[x]^=1;
    swap(ls(x),rs(x));
    swap(dis1[x],dis2[x]);
  }
  return;
}
inline void pushdown(int x){
  if(rev[x]){
    rev[x]=0;
    Rev(ls(x));
    Rev(rs(x));
  }
  return;
}
void dfs(int x){
  if(!x) return;
  pushdown(x);
  debug("x=%d f=%d ls=%d rs=%d w=%lld dis1=(%lld %d) s: ",x,f[x],ls(x),rs(x),w[x],dis1[x].first,dis1[x].second);
  for(pr o:s[x]) debug("(%lld %d) ",o.first,o.second);
  debug("\n");
  dfs(ls(x));dfs(rs(x));
}
void print(){
  for(int i=1;i<=n+n-1;i++){
    if(!nroot(i)) dfs(i);
  }
}
inline void rotate(int x){
  int fa=f[x],gfa=f[fa];
  int d=which(x),son=tr[x][d^1];
  f[x]=gfa;if(nroot(fa)) tr[gfa][which(fa)]=x;
  f[fa]=x;tr[x][d^1]=fa;
  if(son) {f[son]=fa;}tr[fa][d]=son;
  pushup(fa);pushup(x);
  return;
}
int zhan[N];
inline void splay(int x){
  int top=0,y=x;
  zhan[++top]=y;
  while(nroot(y)) zhan[++top]=y=f[y];
  while(top) pushdown(zhan[top--]);
  for(int fa;fa=f[x],nroot(x);rotate(x)){
    if(nroot(fa)) which(fa)==which(x)?rotate(fa):rotate(x);
  }
  return;
}
inline void access(int x){
  for(int y=0;x;y=x,x=f[x]){
    splay(x);
    if(rs(x)){
      s[x].insert(dis1[rs(x)]);
    }
    if(y){
      s[x].erase(s[x].find(dis1[y]));
    }
    rs(x)=y;
    pushup(x);
  }
  return;
}
inline void makeroot(int x){
  access(x);splay(x);Rev(x);
}
inline void link(int x,int y){
  makeroot(x);makeroot(y);
  f[x]=y;
  s[y].insert(dis1[x]);
  pushup(y);
  return;
}

ll mod;
ll D;
int a,b;
signed main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
  #endif
  n=read();m=read();mod=read();
  for(int i=1;i<n;i++){
    int x=read(),y=read();
    w[n+i]=read();
    link(x,n+i);
    link(y,n+i);
  }
  for(int i=1;i<=n;i++){
    makeroot(i);
    if(dis1[i].first>D){
      D=dis1[i].first;
      a=i;b=dis1[i].second;
    }
  }
  ll lst=0;
  while(m--){
    ll x=(read()+lst)%(n-1)+1 +n,ww=(read()+lst)%mod;    
    makeroot(x);
    w[x]=ww;pushup(x);
    int u=a,v=b;
    D=a=b=0;

    makeroot(u);
    if(dis1[u].first>=D){
      D=dis1[u].first;
      a=u;b=dis1[u].second;
    }
    
    makeroot(v);
    if(dis1[v].first>=D){
      D=dis1[v].first;
      a=v;b=dis1[v].second;
    }

    printf("%lld\n",lst=D);
  }
  return 0;
}
/*
*/
 

相关阅读

相关文章

相关问答