CF1192B Dynamic Diameter(LCT)
Foreword\text{Foreword}Foreword
@zhengrunzhe 大佬的矩陣做法過于神奇,蒟蒻無法理解…
歐拉序的做法確實非常巧妙,但我也想不到這么神仙的做法…
提供一種可能簡單一些的 LCT 做法。
由于本人 LCT 無法像大佬那么神,講的會比較詳細一些,也許對其他 LCT 平民玩家更加友好?
Solution\text{Solution}Solution
本題有一個很關鍵的性質:邊權非負。(歐拉序的做法也要基于這個性質)
又發現修改無非改大/小,在/不在原直徑上,利用非負的性質分別討論一下,就會發現新直徑至少有一個節點和原來相同。
所以我們一開始暴力求出直徑后,只需要不斷把原直徑的兩端點提出來,用從二者出發新的最長路徑來嘗試作為新直徑就行了。
所以現在只需要動態維護從一個點出發的最長路徑。
常規套路,先邊化點,邊權化點權。
設 wxw_xwx? 表示 xxx 的點權,sumxsum_xsumx? 表示 xxx splay子樹內點權之和,disxdis_xdisx? 表示從 xxx 所在 splay 子樹內深度最淺的節點出發往子樹延伸的最長路徑。
先不考慮 xxx 實鏈父親,嘗試求出從 xxx 出發往子樹延伸的最長路徑 resxres_xresx?。
一開始有:
resx=wxres_x=w_xresx?=wx?
對于 xxx 的虛兒子,對每個節點開一個 std::set 維護虛子樹,進行轉移:
resx←max?sondisson+wxres_x\gets \max_{son}dis_{son}+w_xresx?←sonmax?disson?+wx?
還有從 xxx 的實兒子轉移,不難發現其對應的就是 disrsxdis_{rs_x}disrsx??:
resx←disrsx+wxres_x\gets dis_{rs_x}+w_xresx?←disrsx??+wx?
求完 resxres_xresx? 后,如果 xxx 沒有左兒子,說明他就是鏈頭,直接讓 disx=resxdis_x=res_xdisx?=resx? 即可;否則,鏈頭可以不使用 resxres_xresx? 的轉移,或者使用 resxres_xresx? 的轉移,那么還要加上 xxx 到鏈頭一段的權值和,分別對應 max 的前后兩項:
disx=max?(dislsx,resx+sumlsx)dis_x=\max(dis_{ls_x},res_x+sum_{ls_x})disx?=max(dislsx??,resx?+sumlsx??)
這樣就做完了。由于轉移不對稱,所以我們還要鏡像的處理一個 dis′xdis'xdis′x,在翻轉時直接交換兩項即可。
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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifn=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; } /* */總結
以上是生活随笔為你收集整理的CF1192B Dynamic Diameter(LCT)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CF1534F:Falling Sand
- 下一篇: 16年的电脑配置(16年电脑配置)