生活随笔
收集整理的這篇文章主要介紹了
[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ò),歡迎將生活随笔 推薦給好友。