日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【LCT】历史(P4338)

發(fā)布時(shí)間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【LCT】历史(P4338) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

P4338


題目大意

有一棵樹,告訴你每個(gè)點(diǎn)access的次數(shù)(帶修改),問實(shí)鏈切換的最多次數(shù)


解題思路

先考慮離線的做法:

對于點(diǎn) x,其不同兒子的子樹access會使實(shí)鏈切換(對于點(diǎn) x access 同理),每次都讓不同兒子的子樹 access,顯然可以讓答案最大化

但答案不一定是 szx?1sz_x-1szx??1(最后無法切換),因?yàn)槿绻嬖谝粋€(gè)兒子 y 滿足 szy>szx?szysz_y > sz_x-sz_yszy?>szx??szy?,即該子樹大小大于其他子樹大小之和,那么不存在操作使得 y 中的每次access都被切換掉

所以當(dāng) szy×2≥szx+1sz_y\times 2\geq sz_x+1szy?×2szx?+1 時(shí)答案為 (szx?szy)×2(sz_x-sz_y)\times 2(szx??szy?)×2(最多切換這么多次不同的), 否則為 szx?1sz_x-1szx??1


然后再考慮在線的做法:

考慮用LCT維護(hù),實(shí)邊連接滿足 szy×2≥szx+1sz_y\times 2\geq sz_x+1szy?×2szx?+1 的兒子(不存在則不連)

每次修改可能會修改當(dāng)前點(diǎn)到根節(jié)點(diǎn)的實(shí)鏈,那么只需考慮對該段的影響

對于原來是實(shí)邊的,顯然加了之后仍然滿足,不影響,對于原來是虛邊的,先減去原來的貢獻(xiàn),然后再考慮連邊計(jì)算貢獻(xiàn)

每經(jīng)過一次虛邊,那么其他兒子的 sz 就必定大于 當(dāng)前點(diǎn)的 sz,那么sz至少會變大一倍,所以最多經(jīng)過 log 條虛邊

時(shí)間復(fù)雜度 O(nlogn)O(n\ log\ n)O(n?log?n)


code

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; #define N 400400 ll n,m,x,y,tot,ans,top,a[N],h[N],d[N]; struct rec {ll to,nx; }e[N<<1]; void add(ll x,ll y) {e[++tot].to=y;e[tot].nx=h[x];h[x]=tot;return; } struct LCT {#define ls son[x][0]#define rs son[x][1]ll v[N],ss[N],s[N],fa[N],son[N][2];bool NR(ll x){return fa[x]&&(son[fa[x]][0]==x||son[fa[x]][1]==x);}bool IRS(ll x){return son[fa[x]][1]==x;}void push_up(ll x){s[x]=s[ls]+s[rs]+ss[x]+v[x];return;}void rotate(ll x){ll y=fa[x],z=fa[y],k=IRS(x),g=son[x][!k];if(NR(y))son[z][IRS(y)]=x;if(g)fa[g]=y;fa[x]=z;fa[y]=x;son[x][!k]=y;son[y][k]=g;push_up(y);return;}void Splay(ll x){while(NR(x)){if(NR(fa[x])){if(IRS(x)==IRS(fa[x]))rotate(fa[x]);else rotate(x);}rotate(x);}push_up(x);return;}ll get(ll x){if(rs)return (v[x]+ss[x])*2;else if(v[x]*2>=(s[x]-s[ls])+1)return ss[x]*2;else return (s[x]-s[ls])-1;}void access(ll x,ll z){Splay(x);ans-=get(x);//減去原有貢獻(xiàn)v[x]+=z;s[x]+=z;if(rs&&s[rs]*2<s[x]-s[ls]+1){//斷去原來的邊ss[x]+=s[rs];rs=0;}ans+=get(x);ll y=x;x=fa[x];for(;x;x=fa[y=x]){Splay(x);ans-=get(x);ss[x]+=z;s[x]+=z;if(rs&&s[rs]*2<s[x]-s[ls]+1){ss[x]+=s[rs];rs=0;}if(s[y]*2>=s[x]-s[ls]+1){//連接新的實(shí)邊rs=y;ss[x]-=s[rs];}ans+=get(x);}return;} }T; void dfs(ll x)//初始連邊 {ll hs=0;T.v[x]=a[x];for(ll i=h[x];i;i=e[i].nx){ll y=e[i].to;if(y==T.fa[x])continue;T.fa[y]=x;dfs(y);T.ss[x]+=T.s[y];if(T.s[y]>T.s[hs])hs=y;}T.s[x]=T.v[x]+T.ss[x];if(T.s[hs]*2>=T.s[x]+1){T.son[x][1]=hs;T.ss[x]-=T.s[hs];ans+=(T.v[x]+T.ss[x])*2;}else if(T.v[x]*2>=T.s[x]+1){ans+=T.ss[x]*2;}else ans+=T.s[x]-1;return; } int main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;++i)scanf("%lld",&a[i]);for(ll i=1;i<n;++i){scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}dfs(1);printf("%lld\n",ans);while(m--){scanf("%lld%lld",&x,&y);T.access(x,y);printf("%lld\n",ans);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的【LCT】历史(P4338)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。