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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ 3731: Gty的超级妹子树

發布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 3731: Gty的超级妹子树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

我曾在青山之中遇過你,

新竹做杖,鬢插紫茱萸。

跣足踏過無邊絲雨,

又拾起燕川雪片片落如席……

Gty神(xian)犇(chong)從來不缺妹子……

他又來到了一棵妹子樹下,發現每個妹子有一個美麗度……

由于Gty很 哲♂學 也很 機♂智,他只對美麗度大于某個值的妹子感興趣。

他想知道某個子樹中美麗度大于x的妹子個數。

某個妹子的美麗度可能發生變化……

樹上可能會出現一只新的妹子……

但是……樹枝可能會斷裂,于是,Gty驚訝地發現,他的面前變成了一片妹子樹組成的森林……

維護一棵初始有n個節點的有根樹(根節點為1),樹上節點編號為1-n,每個點有一個權值wi。它可能會變成森林。

支持以下操作:

0 u x 詢問以u為根的子樹中,嚴格大于x的值的個數。(u=lastans,x=lastans)

1 u x 把u節點的權值改成x。(u=lastans,x=lastans)

2 u x 添加一個編號為"當前樹中節點數+1"的節點,其父節點為u,其權值為x。(u=lastans,x=lastans)

3 u 刪除節點u與其父節點之間的路徑。此時u的父節點變成葉子節點,u變成分裂出的樹的根。(u^=lastans)

最開始時lastans=0。

Input

輸入第一行包括一個正整數n(1<=n<=100000),代表樹上的初始節點數。

接下來n-1行,每行2個整數u,v,為樹上的一條無向邊。

任何時刻,樹上的任何權值大于等于0,且兩兩不同。

接下來1行,包括n個整數wi,表示初始時每個節點的權值。

接下來1行,包括1個整數m(1<=m<=100000),表示操作總數。

接下來m行,每行最開始包括一個整數op,

若op=3,該行還會有一個整數u;

若op不等于3,該行還會有兩個整數u,x;

op,u,x的范圍見題目描述。

保證題目涉及的所有數在int內。

Output

對每個op=0,輸出一行,包括一個整數,意義見題目描述。

Sample Input

2

1 2

10 20

1

0 1 5

Sample Output

2

Solution

  • bzoj 3720 相比,本題多了一個斷邊操作。

  • 這題的解法是樹分塊,顧名思義就是將樹分成一塊一塊的。

  • 具體來說就是設置一個閾值 limlimlim ,并將樹根設為第 111 塊。

  • 開始遞歸到下一個點 xxx ,若上一個點所在塊的 size&lt;limsize&lt;limsize<lim ,則將 xxx 也歸入上一個塊;

  • 若上一個點所在塊的 sizesizesize 已經 =lim=lim=lim 了,那么就將 xxx 作為新的一個塊的根。

  • 這樣遞歸下去,樹就被分成了 nlim\frac{n}{lim}limn? 個塊了。

  • 對于每個塊中的點,我們開一個 vectorvectorvector 記錄其排好序的權值。

  • 對于查詢操作,散塊暴力,整塊查詢 ,從查詢點先遍歷幾個散點,之后就能直接跑整塊了,這樣跑的整塊和散點個數都是有限的,因為有著 limlimlim 的限制。每個整塊中二分出符合條件的位置即可。

  • 對于修改操作,我們直接在修改點所在塊的 vectorvectorvector 中把該點的權值找出來,替換成新權值,注意此時應維護 vectorvectorvector 中元素的有序性。

  • 對于加點操作,我們和當初樹分塊一樣即可(看看能不能歸入父親節點所在塊),注意當能加入舊塊時,仍要保持 vectorvectorvector 元素的有序性。

  • 對于刪除操作 ,若刪除點為一個塊的根節點,則直接斷開其跟上一個塊的連邊;否則就將該點下面的建成一個新的塊,多注意細節即可。

  • 這樣處理就能較好地保證各操作的復雜度,注意常數即可通過本題。

  • 若閾值 limlimlim 設為 n\sqrt nn? ,則本題復雜度約為 O(nnlogn)O(n\sqrt n\ log\ n)O(nn??log?n)

  • 由于塊的個數多反而常數大,我們可以使 limlimlim 設得稍大一點,如 lim=nlognlim=\sqrt{n\ log\ n}lim=n?log?n?

  • 這樣就能跑得挺快的了。

  • 唯一美中不足的是樹分塊做法似乎能被菊花圖卡(塊的個數不可抑制的變得特別多)。

  • 但是本題好像沒有別的做法了,這也許就是我們應該努力的地方啊!

Code

#include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<cctype> using namespace std; const int N=2e5+5; int cnt,lim,last,val; int w[N],id[N],size[N],fa[N],head[N]; vector<int>ss[N],e[N],e1[N]; vector<int>::iterator it; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline void insert(int x,int y) {e[x].push_back(y);e[y].push_back(x); } inline void insert1(int x,int y) {e1[x].push_back(y); } void dfs(int x) {id[x]=cnt;size[cnt]++;ss[cnt].push_back(w[x]);for(int i=0;i<(int)e[x].size();i++){int to=e[x][i];if(to^fa[x]){fa[to]=x;if(size[id[x]]==lim){head[++cnt]=to;insert1(id[x],cnt);}dfs(to);}} } void dfs2(int x) {last+=ss[x].size()-(upper_bound(ss[x].begin(),ss[x].end()--,val)-ss[x].begin());for(int i=0;i<(int)e1[x].size();i++) dfs2(e1[x][i]); } void dfs1(int x) {last+=w[x]>val;for(int i=0;i<(int)e[x].size();i++){int to=e[x][i];if(to^fa[x])if(id[to]==id[x]) dfs1(to); else dfs2(id[to]);} } inline void del(int x,int y) {e[x].erase(find(e[x].begin(),e[x].end(),y));e[y].erase(find(e[y].begin(),e[y].end(),x)); } inline void del1(int x,int y) {it=find(e1[x].begin(),e1[x].end(),y);if(it!=e1[x].end()) e1[x].erase(it); } void dfs3(int x) {id[x]=cnt;size[cnt]++;ss[cnt].push_back(w[x]);for(int i=0;i<(int)e[x].size();i++){int to=e[x][i];if(to^fa[x])if(id[to]==val) dfs3(to); else{del1(val,id[to]);insert1(cnt,id[to]);}} } int main() {freopen("bzoj3731.in","r",stdin);freopen("bzoj3731.out","w",stdout);int n=read();for(int i=1;i<n;i++) insert(read(),read());for(int i=1;i<=n;i++) w[i]=read();lim=ceil(sqrt(n*log2(n)));head[cnt=1]=1;dfs(1);for(int i=1;i<=cnt;i++) sort(ss[i].begin(),ss[i].end());int m=read();while(m--){int op=read(),x=read()^last;//int op=read(),x=read();if(op==3){if(head[id[x]]==x){if(fa[x]){del(x,fa[x]);del1(id[fa[x]],id[x]);}}else{del(x,fa[x]);val=id[x];head[++cnt]=x;dfs3(x);sort(ss[cnt].begin(),ss[cnt].end());int idfa=id[fa[x]];size[idfa]-=size[cnt];for(int i=0;i<(int)ss[cnt].size();i++){int pos=lower_bound(ss[idfa].begin(),ss[idfa].end()--,ss[cnt][i])-ss[idfa].begin();ss[idfa].erase(ss[idfa].begin()+pos);}}}else{int y=read()^last;//int y=read();if(!op){last=0;val=y;if(head[id[x]]==x) dfs2(id[x]); else dfs1(x);write(last),putchar('\n');}elseif(op==1){int idx=id[x],pos=lower_bound(ss[idx].begin(),ss[idx].end()--,w[x])-ss[idx].begin();if(y<ss[idx][pos]){while(pos && ss[idx][pos-1]>y){ss[idx][pos]=ss[idx][pos-1];pos--;}ss[idx][pos]=y;}else{int up=ss[idx].size()-1;while(pos<up && ss[idx][pos+1]<y){ss[idx][pos]=ss[idx][pos+1];pos++;}ss[idx][pos]=y;}w[x]=y;}else{fa[++n]=x;w[n]=y;insert(x,n);if(size[id[x]]==lim){head[++cnt]=n;size[cnt]=1;id[n]=cnt;ss[cnt].push_back(y);insert1(id[x],cnt);}else{int idx=id[n]=id[x];size[idx]++;bool pd=false;for(int i=0;i<(int)ss[idx].size();i++)if(ss[idx][i]>y){pd=true;ss[idx].push_back(0);for(int j=ss[idx].size()-1;j>i;j--) ss[idx][j]=ss[idx][j-1];ss[idx][i]=y;break;}if(!pd) ss[idx].push_back(y);}}}}return 0; }

總結

以上是生活随笔為你收集整理的BZOJ 3731: Gty的超级妹子树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。