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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

HDU - 7009 树上游走(树的直径+容斥)

發(fā)布時(shí)間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 7009 树上游走(树的直径+容斥) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接:點(diǎn)擊查看

題目大意:給一棵樹,稱一個(gè)點(diǎn)集 S 是好的當(dāng)且僅當(dāng)存在一個(gè)點(diǎn),其到 S 中所有點(diǎn)的距離互不相同,求 |S| 的最大值和使得 |S| 最大的 S 的個(gè)數(shù)

題目分析:不難看出 ∣S∣|S|S 就是樹的直徑,而滿足條件的 SSS 的個(gè)數(shù),無(wú)非就是枚舉每個(gè)點(diǎn)作為樹的根節(jié)點(diǎn),然后將 nnn 個(gè)節(jié)點(diǎn)按層劃分,每一層恰好選擇一個(gè)點(diǎn)的方案數(shù),這個(gè)可以根據(jù)乘法原理,將每一層節(jié)點(diǎn)的個(gè)數(shù)累乘起來(lái)即可。這樣確實(shí)可以計(jì)算出所有的答案,但是會(huì)有重復(fù)。

不過(guò)通過(guò)思考后可以看出,重復(fù)的部分當(dāng)且僅當(dāng) SSS 中的點(diǎn)是一條鏈的時(shí)候,又因?yàn)?∣S∣|S|S 是樹的直徑,所以這條鏈也對(duì)應(yīng)著樹上的一條直徑

維護(hù)答案的同時(shí),順便維護(hù)一下樹的直徑有多少條即可

2021.8.4 UPDATE:

感謝vjudge巨巨的hack樣例:

之前也是感覺(jué)這個(gè)題重復(fù)的部分不只是直徑那么簡(jiǎn)單,但是看到題解和AC代碼都是這個(gè)思路就不了了之了,補(bǔ)多校的題補(bǔ)的也沒(méi)時(shí)間去糾結(jié)這些小問(wèn)題了。但是這位巨巨的樣例體現(xiàn)出了,重復(fù)的部分不一定是連續(xù)的一條鏈,所以我們?cè)撊绾稳フ_的容斥呢?

首先統(tǒng)計(jì)貢獻(xiàn)的部分是沒(méi)有問(wèn)題的,就是枚舉每個(gè)節(jié)點(diǎn)作為根節(jié)點(diǎn),將所有節(jié)點(diǎn)按照深度分類,然后累乘起來(lái),下面重點(diǎn)講一下如何容斥去重。

假設(shè)我們目前枚舉到了以點(diǎn) xxx 為根節(jié)點(diǎn)的樹,先前已經(jīng)處理過(guò)了根節(jié)點(diǎn)為 yyy 的樹,保證點(diǎn) xxx 和點(diǎn) yyy 都是樹的直徑的端點(diǎn)。當(dāng)我們將這個(gè)形態(tài)的樹,都按照深度“拉直”后,設(shè)兩點(diǎn)之間的深度差為 deltadeltadelta 不難發(fā)現(xiàn)深度位于 delta+1delta+1delta+1 及之后的位置,兩棵樹相應(yīng)位置的形態(tài)是完全一樣的,也就是說(shuō)在這里會(huì)被重復(fù)統(tǒng)計(jì),所以我們對(duì)于 cntcntcnt 維護(hù)一個(gè)后綴乘積,減去相應(yīng)的答案即可

相比于之前的代碼多了點(diǎn)常數(shù),懶得卡常了,留一份TLE的代碼

代碼:

// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; const int mod=998244353; vector<int>node[N]; int cnt[N],deep[N],max_deep; bool vis[N]; void dfs(int u,int fa,int dep) {cnt[dep]++;deep[u]=dep;max_deep=max(max_deep,dep);for(auto v:node[u]) {if(v==fa) {continue;}dfs(v,u,dep+1);} } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;while(w--) {int n;read(n);for(int i=1;i<=n;i++) {node[i].clear();vis[i]=false;}for(int i=1;i<n;i++) {int u,v;read(u),read(v);node[u].push_back(v);node[v].push_back(u);}int mmax=-1;for(int rt=1;rt<=n;rt++) {dfs(rt,-1,1);}mmax=max_deep;for(int rt=1;rt<=n;rt++) {max_deep=0;dfs(rt,-1,1);if(max_deep==mmax) {vis[rt]=true;}}LL ans=0;for(int rt=1;rt<=n;rt++) {if(!vis[rt]) {continue;}memset(cnt,0,sizeof(int)*(n+5));dfs(rt,-1,1);cnt[mmax+1]=1;for(int i=mmax;i>=1;i--) {cnt[i]=(1LL*cnt[i]*cnt[i+1])%mod;}ans=(ans+cnt[1])%mod;for(int x=1;x<rt;x++) {if(vis[x]) {ans=(ans+mod-cnt[deep[x]+1])%mod;}}}cout<<mmax<<' '<<ans<<endl;}return 0; }

總結(jié)

以上是生活随笔為你收集整理的HDU - 7009 树上游走(树的直径+容斥)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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