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<limsize<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的超级妹子树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5952. 【NOIP2018
- 下一篇: NOIP2018 赛前集训总结反思