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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[ZJOI2016]大森林

發(fā)布時(shí)間:2025/3/15 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [ZJOI2016]大森林 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Description:

小Y家里有一個(gè)大森林,里面有n棵樹,編號從1到n

0 l r 表示將第 l 棵樹到第 r 棵樹的生長節(jié)點(diǎn)下面長出一個(gè)子節(jié)點(diǎn),子節(jié)點(diǎn)的標(biāo)號為上一個(gè) 0 號操作葉子標(biāo)號加 1(例如,第一個(gè) 0 號操作產(chǎn)生的子節(jié)點(diǎn)標(biāo)號為 2), l 到 r 之間的樹長出的節(jié)點(diǎn)標(biāo)號都相同。保證 1<=l<=r<=n 。

1 l r x 表示將第 l 棵樹到第 r 棵樹的生長節(jié)點(diǎn)改到標(biāo)號為 x 的節(jié)點(diǎn)。對于 i (l<=i<=r)這棵樹,如果標(biāo)號 x的點(diǎn)不在其中,那么這個(gè)操作對該樹不產(chǎn)生影響。保證 1<=l<=r<=n , x 不超過當(dāng)前所有樹中節(jié)點(diǎn)最大的標(biāo)號。

2 x u v 詢問第 x 棵樹中節(jié)點(diǎn) u 到節(jié)點(diǎn) v 點(diǎn)的距離,也就是在第 x 棵樹中從節(jié)點(diǎn) u 和節(jié)點(diǎn) v 的最短路上邊的數(shù)量。保證1<=x<=n,這棵樹中節(jié)點(diǎn) u 和節(jié)點(diǎn) v 存在。

Hint:

$ N<=10^5,M<=2*10^5 $

Solution:

一開始想到線段樹套LCT,然而標(biāo)記無法下傳
考慮樸素做法,每個(gè)節(jié)點(diǎn)用LCT維護(hù)一片森林,空間顯然無法承受
這時(shí)我們需要轉(zhuǎn)換思路
因?yàn)轭}目沒有強(qiáng)制在線,所以我們可以只維護(hù)一顆”樹“,然后按順序處理1、2操作
每次1操作直接把該生長節(jié)點(diǎn)的子樹”嫁接“到另一個(gè)生長節(jié)點(diǎn)
為了保證復(fù)雜度,我們需要在生長節(jié)點(diǎn)處開一個(gè)虛點(diǎn),這樣就不需要多點(diǎn)換父親了
2操作直接用求個(gè)LCA就行了

#include<bits/stdc++.h> using namespace std; const int mxn=3e5+5; struct Q {int pos,id,x,y,qr; }q[mxn]; int n,m,p,s,tot,cnt,sum; int t[mxn],lp[mxn],rp[mxn],bl[mxn],fa[mxn],ch[mxn][2],ans[mxn],val[mxn];int cmp(Q x,Q y) {return x.pos==y.pos?x.id<y.id:x.pos<y.pos; }namespace lct {int isnotrt(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}void push_up(int x) {t[x]=t[ch[x][0]]+t[ch[x][1]]+val[x];}void rotate(int x) {int y=fa[x],z=fa[y],tp=ch[y][1]==x;if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;ch[y][tp]=ch[x][tp^1]; fa[ch[x][tp^1]]=y;ch[x][tp^1]=y; fa[y]=x;push_up(y),push_up(x);}void splay(int x) {while(isnotrt(x)) {int y=fa[x],z=fa[y];if(isnotrt(y)) (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);rotate(x); }}int access(int x) {int y;for(y=0;x;x=fa[y=x]) splay(x),ch[x][1]=y,push_up(x);return y; }void link(int x,int y) {splay(x); fa[x]=y;}void cut(int x) {access(x); splay(x); ch[x][0]=fa[ch[x][0]]=0; push_up(x);} } using namespace lct;int main() {scanf("%d%d",&n,&m); int res,lca,opt,l,r,x,y; p=tot=val[1]=t[1]=lp[1]=bl[1]=1; rp[1]=n; int now=2; link(++p,1);for(int i=1;i<=m;++i) {scanf("%d",&opt);if(opt==0) {scanf("%d%d",&l,&r);bl[++tot]=++p; link(p,now); //每次把新節(jié)點(diǎn)直接長在最近更新的生成節(jié)點(diǎn),考慮這樣為什么不會(huì)錯(cuò),因?yàn)閷?shí)點(diǎn)之間的虛點(diǎn)不會(huì)影響答案lp[tot]=l,rp[tot]=r; val[p]=t[p]=1;}else if(opt==1) {scanf("%d%d%d",&l,&r,&x); l=max(l,lp[x]); r=min(r,rp[x]); if(l>r) continue;//去掉無用的區(qū)間link(++p,now);q[++s]=(Q){l,i,p,bl[x],0};q[++s]=(Q){r+1,i,p,now,0};now=p;}else scanf("%d%d%d",&l,&x,&y),q[++s]=(Q){l,i,bl[x],bl[y],++sum};}sort(q+1,q+s+1,cmp); for(int i=1;i<=s;++i) {if(q[i].qr>0) {access(q[i].x); splay(q[i].x); res=t[q[i].x]; //因?yàn)檫@題規(guī)定根為1,所以我們不能makertlca=access(q[i].y); splay(q[i].y); res+=t[q[i].y];access(lca); ans[q[i].ss]=res-t[lca]*2; }else cut(q[i].x),link(q[i].x,q[i].y);}for(int i=1;i<=sum;++i) printf("%d\n",ans[i]);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/list1/p/10421740.html

總結(jié)

以上是生活随笔為你收集整理的[ZJOI2016]大森林的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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