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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

P5666-[CSP-S2019]树的重心【树状数组】

發(fā)布時(shí)間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P5666-[CSP-S2019]树的重心【树状数组】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P5666


題目大意

給出nnn個(gè)點(diǎn)的一棵樹,對于每條邊割掉后兩棵樹重心編號(hào)和。

1≤T≤5,1≤n≤2999951\leq T\leq 5,1\leq n\leq 2999951T5,1n299995


解題思路

編號(hào)和,所以應(yīng)該是要我們枚舉點(diǎn)然后求有多少條邊割掉后它能當(dāng)重心。

隨便以一個(gè)點(diǎn)為根的話,對于一個(gè)點(diǎn),割掉它子樹外面的一條邊,設(shè)割去的連通塊大小為kkk那么需要滿足,以及點(diǎn)xxx的最大子節(jié)點(diǎn)子樹為fxf_xfx?
{2(n?k?sx)≤n?S2fx≤n?k\left\{\begin{matrix}2(n-k-s_x)\leq n-S\\2f_x\leq n-k\end{matrix}\right.{2(n?k?sx?)n?S2fx?n?k?
移一下項(xiàng)就有
n?2sx≤k≤n?2fxn-2s_x\leq k\leq n-2f_xn?2sx?kn?2fx?

但是子樹里面就很難搞了,因?yàn)槲覀冃枰S護(hù)子樹里所有子樹的大小,其中一種方法是用線段樹合并或者主席樹像YbtOJ#662-交通運(yùn)輸這題一樣搞。

很麻煩對啊吧,轉(zhuǎn)換一下思路。其實(shí)有一個(gè)性質(zhì)就是如果我們選擇了原樹的重心作為根節(jié)點(diǎn),那么子節(jié)點(diǎn)無論如何割掉子樹中的邊也不會(huì)是重心。

所以這樣就可以去掉這種麻煩的情況了。

只考慮前面那種,我們需要找到分割大小在[n?2sx,n?2fx][n-2s_x,n-2f_x][n?2sx?,n?2fx?]這個(gè)區(qū)間的邊,并且還要不在子樹內(nèi)。

如果不考慮不在子樹內(nèi)的話挺好搞,對于根節(jié)點(diǎn)到該節(jié)點(diǎn)的路徑都是n?sizxn-siz_xn?sizx?,否則是sizxsiz_xsizx?丟進(jìn)樹狀數(shù)組里查詢就好了,邊往下做邊改樹狀數(shù)組就好了。

還要減去子樹內(nèi)的,好像還是要和上面一樣用線段樹合并?

我們可以用進(jìn)入子樹后的總共答案減去進(jìn)入子樹前的總共答案就是子樹里面的答案了

這樣好寫很多,時(shí)間復(fù)雜度O(nlog?n)O(n\log n)O(nlogn)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define lowbit(x) (x&-x) using namespace std; const ll N=3e5+10; struct node{ll to,next; }a[N<<1]; ll T,n,ans,tot,rt,u,v; ll siz[N],f[N],ls[N],t1[N],t2[N]; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void Change(ll *t,ll x,ll val){x++;while(x<=n+1){t[x]+=val;x+=lowbit(x);}return; } ll Ask(ll *t,ll x){ll ans=0;x++;if(x>=n+1)x=n+1;else if(x<0)x=0;while(x){ans+=t[x];x-=lowbit(x);}return ans; } void dfs(ll x,ll fa){siz[x]=1;f[x]=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);}if(max(f[x],n-siz[x])<=n/2)rt=x;return; } void calc(ll x,ll fa,bool flag){Change(t1,siz[fa],-1);Change(t1,n-siz[x],1);ll tmp=Ask(t1,n-2*f[x])-Ask(t1,n-2*siz[x]-1);tmp+=Ask(t2,n-2*f[x])-Ask(t2,n-2*siz[x]-1);ans+=tmp*x;ans+=rt*(siz[x]<=n-2*siz[flag?v:u]);Change(t2,siz[x],1);for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;calc(y,x,flag);}Change(t1,siz[fa],1);Change(t1,n-siz[x],-1);ans-=(Ask(t2,n-2*f[x])-Ask(t2,n-2*siz[x]-1))*x; } signed main() {scanf("%lld",&T);while(T--){memset(ls,0,sizeof(ls));tot=rt=ans=u=v=0;scanf("%lld",&n);for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}dfs(1,0);dfs(rt,0);for(ll i=ls[rt];i;i=a[i].next){ll y=a[i].to;if(siz[y]>siz[u])v=u,u=y;else if(siz[y]>siz[v])v=y;} memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));for(ll i=1;i<=n;i++)Change(t1,siz[i],1);for(ll i=ls[rt];i;i=a[i].next)calc(a[i].to,rt,(a[i].to==u));printf("%lld\n",ans);} return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的P5666-[CSP-S2019]树的重心【树状数组】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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