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

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

生活随笔

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

编程问答

中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)

發(fā)布時(shí)間:2024/4/11 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

題目大意:給出一棵 n 個(gè)節(jié)點(diǎn)的樹(shù),以點(diǎn) 1 為根,現(xiàn)在對(duì)于每個(gè)節(jié)點(diǎn)作為根的子樹(shù)求解:子樹(shù)中有多少個(gè)編號(hào)不相交的連續(xù)子段,如:1 2 4 5 7,共有三個(gè)連續(xù)的段,分別為 [ 1 , 2 ] , [ 4 , 5 ] , [ 7 ]

題目分析:樹(shù)上啟發(fā)式合并的模板題,cal 函數(shù)中直接維護(hù)一個(gè)數(shù)組用來(lái)統(tǒng)計(jì)加入或刪除掉一個(gè)數(shù)字后對(duì)于貢獻(xiàn)的影響即可:

  • 如果編號(hào) x - 1 和 x + 1 早已存在,那么加入 x 后總段數(shù)減一
  • 如果編號(hào) x - 1 或 x + 1 早已存在,那么加入 x 后總段數(shù)不變
  • 如果編號(hào) x - 1 和 x + 1 都不存在,那么加入 x 后總段數(shù)加一
  • 刪除的話(huà)正好反過(guò)來(lái)

    然后,今下午在和 zx 學(xué)長(zhǎng)閑聊的時(shí)候,意外發(fā)現(xiàn)這個(gè)題目可以用主席樹(shù)亂搞,因?yàn)樽訕?shù)對(duì)應(yīng)的剛好是 dfs 序,區(qū)間內(nèi)有多少個(gè)不相交的連續(xù)子段也可以用線(xiàn)段樹(shù)的區(qū)間合并來(lái)解決,興致勃勃來(lái)到電腦前面實(shí)現(xiàn),卻發(fā)現(xiàn)了些許問(wèn)題:

  • 對(duì)于每個(gè)節(jié)點(diǎn)如果只維護(hù) sum(有多少個(gè)子段),ll(最左端是否有數(shù)字),rr(最右端是否有數(shù)字),無(wú)法直接計(jì)算出區(qū)間內(nèi)的答案
  • 由上可知,如果想要維護(hù)出正確的答案,需要從葉子節(jié)點(diǎn)再自底向上 pushup 一次
  • 那么總時(shí)間復(fù)雜度為 n^2logn,還不如直接 n*n 的暴力跑得快
  • 于是可持久化線(xiàn)段樹(shù)的區(qū)間合并就沒(méi)辦法了,也可能是我知識(shí)淺薄不會(huì)實(shí)現(xiàn),抱著試一試的心態(tài)去百度了一下題解,發(fā)現(xiàn)這個(gè)題目真的可以用主席樹(shù)來(lái)實(shí)現(xiàn),只不過(guò)需要轉(zhuǎn)換一下模型:

    對(duì)于每個(gè)數(shù)字 x 來(lái)說(shuō),假設(shè)其只與前驅(qū),也就是 x - 1 有關(guān)聯(lián),再假設(shè)當(dāng)前如果有 num 個(gè)數(shù),如果其中有 cnt 個(gè)數(shù)的前驅(qū)也在這 num 個(gè)數(shù)當(dāng)中,那么這 cnt 個(gè)數(shù)都可以和前驅(qū)合并,對(duì)答案不做貢獻(xiàn),所以最后的不相交連續(xù)子段的個(gè)數(shù)是 num - cnt 個(gè)

    這樣問(wèn)題就轉(zhuǎn)換為了:對(duì)于某個(gè)節(jié)點(diǎn)來(lái)說(shuō),其子樹(shù)中有多少個(gè)節(jié)點(diǎn)的前驅(qū)也在子樹(shù)中,答案就是子樹(shù)的大小與這個(gè)做差了

    代碼:

    樹(shù)上啟發(fā)式合并

    #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> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100;vector<int>node[N];int ans[N],son[N],num[N],sum;bool vis[N],book[N];void dfs_son(int u,int fa)//樹(shù)鏈剖分跑出重鏈 {son[u]=-1;num[u]=1;for(auto v:node[u]){if(v==fa)continue;dfs_son(v,u);num[u]+=num[v];if(son[u]==-1||num[v]>num[son[u]])son[u]=v;} }void cal(int u,int fa,int val)//對(duì)于每個(gè)節(jié)點(diǎn)計(jì)算其子樹(shù)的貢獻(xiàn) {if(val==1){book[u]=true;if(book[u-1]&&book[u+1])sum--;else if(book[u-1]||book[u+1]);elsesum++;}else{book[u]=false;if(book[u-1]&&book[u+1])sum++;else if(book[u-1]||book[u+1]);elsesum--;}for(auto v:node[u]){if(v==fa||vis[v])continue;cal(v,u,val);} }void dfs(int u,int fa,int keep)//啟發(fā)式合并 {for(auto v:node[u]){if(v==fa||v==son[u])continue;dfs(v,u,0);}if(son[u]!=-1){dfs(son[u],u,1);vis[son[u]]=true;}cal(u,fa,1);ans[u]=sum;if(son[u]!=-1)vis[son[u]]=false;if(!keep)cal(u,fa,-1); }void init(int n) {for(int i=1;i<=n;i++)node[i].clear();memset(vis,false,n+5);memset(book,false,n+5);sum=0; }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;int kase=0;while(w--){int n;scanf("%d",&n);init(n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}dfs_son(1,-1);dfs(1,-1,1);printf("Case #%d:",++kase);for(int i=1;i<=n;i++)printf(" %d",ans[i]);puts("");}return 0; }

    主席樹(shù)

    #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> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100; /*主席樹(shù)*/ struct Node {int l,r;int sum; }tree[N*20];int cnt,root[N];void update(int pos,int &k,int l,int r) {if(pos<l||pos>r)return;tree[cnt++]=tree[k];k=cnt-1;tree[k].sum++;if(l==r)return;int mid=l+r>>1;if(pos<=mid)update(pos,tree[k].l,l,mid);elseupdate(pos,tree[k].r,mid+1,r); }int query(int i,int j,int l,int r,int L,int R)//[l,r]:目標(biāo)區(qū)間,[L,R]:當(dāng)前區(qū)間 {if(R<l||L>r)return 0;if(L>=l&&R<=r)return tree[j].sum-tree[i].sum;int mid=L+R>>1;return query(tree[i].l,tree[j].l,l,r,L,mid)+query(tree[i].r,tree[j].r,l,r,mid+1,R); } /*主席樹(shù)*/ /*dfs序*/ vector<int>node[N];int L[N],R[N],tot,id[N],sz[N]; void dfs(int u,int fa) {sz[u]=1;L[u]=++tot;id[tot]=u;for(auto v:node[u]){if(v==fa)continue;dfs(v,u);sz[u]+=sz[v];}R[u]=tot; } /*dfs序*/ void init(int n) {root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1;tot=0;for(int i=1;i<=n;i++)node[i].clear(); }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;int kase=0;while(w--){int n;scanf("%d",&n);init(n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}dfs(1,-1);for(int i=1;i<=n;i++)//遍歷dfs序建樹(shù) {root[i]=root[i-1];update(L[id[i]-1],root[i],1,n);//第i個(gè)dfs序表示的節(jié)點(diǎn)是id[i],其前驅(qū)為id[i]-1,將其前驅(qū)的dfs序標(biāo)記一下}printf("Case #%d:",++kase);for(int i=1;i<=n;i++)printf(" %d",sz[i]-query(root[L[i]-1],root[R[i]],L[i],R[i],1,n));//查找時(shí)只需要查找子樹(shù)中的點(diǎn)的前驅(qū)個(gè)數(shù)即可puts("");}return 0; }

    ?

    總結(jié)

    以上是生活随笔為你收集整理的中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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