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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

BZOJ 3720 [洛谷P2137] : Gty的妹子树

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

Description

我曾在弦歌之中聽過你,

檀板聲碎,半出折子戲。

舞榭歌臺被風吹去,

歲月深處尚有余音一縷……

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

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

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

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

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

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

維護一棵初始有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)

最開始時lastans=0。

Input

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

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

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

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

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

接下來m行,每行包括三個整數 op,u,v:

op,u,v的含義見題目描述。

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

Output

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

Sample Input

2

1 2

10 20

1

0 1 5

Sample Output

2

Solution

  • 大家多用的是樹分塊的方法,這里我用的歸并樹+定期重構。

  • 具體怎樣呢?關鍵是我們考慮每個修改對之后詢問的影響。

  • 如果沒有修改(靜態詢問),我們對dfs序建歸并樹,直接區間查詢即可。

  • (歸并樹就是一種線段樹,區間內存的是這個區間權值排序后的序列,查詢時在上面二分)

  • 有了修改,我們就要判斷修改對詢問有影響,其中修改點要在詢問點的子樹內。

  • 如何判斷是否在子樹內:倍增跳。加點時處理出其 2i2^i2i 級父親。

  • 于是我們得到這樣一個算法:我們在歸并樹中查詢后,針對若干修改操作暴力判斷影響。

  • 那我們就可以定期重構啦!

  • 如果我們在查詢之前的修改不超過 m\sqrt mm? 次時,就在歸并樹上查詢后暴力掃描修改計算貢獻;

  • 如果修改超過了 m\sqrt mm? 次時,我們只要根據修改重建一下歸并樹就可以清除掉這些修改,

  • 可以發現歸并樹的重建不會超過 m\sqrt mm? 次。

  • 那么我們來分析一下復雜度:(假設 n,mn,mn,m 同階)

  • 每次掃描修改算貢獻,修改最多 n\sqrt nn? 個,每次倍增判是否在子樹要 O(logn)O(log\ n)O(log?n) ,復雜度為 O(nnlogn)O(n\sqrt n\ log\ n)O(nn??log?n) 。

  • 每次重建歸并樹要 O(nlogn)O(n\ log\ n)O(n?log?n) ,最多重建 O(logn)O(log\ n)O(log?n) 次,故復雜度同是 O(nnlogn)O(n\sqrt n\ log\ n)O(nn??log?n)

  • 于是這題就解決了,總時間復雜度 O(nnlogn)O(n\sqrt n\ log\ n)O(nn??log?n)

  • 有一些細節要注意:

  • 由于重建歸并樹常數比較大,我們可以多幾次修改再重建一次,比如說 5?n5*\sqrt n5?n?

  • 還有就是打線段樹詢問時:find(1,1,n)find(1,1,n)find(1,1,n) ,由于加點時 nnn 會增加,但帶進詢問時仍然要是之前的 nnn ,不然就不對了,重構時再把 find(1,1,n)find(1,1,n)find(1,1,n)nnn 改成新的。

Code

#include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<cctype> using namespace std; const int N=60005; struct data {int op,x,y,z; }q[N>>1]; int n,tot,num,cnt,qx,qy,qz,last,lim; int first[N],nex[N<<1],en[N<<1]; int w[N],dfn[N],size[N],id[N],dep[N],fa[N][16]; vector<int>ss[N<<2]; 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) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } void dfs(int x) {dfn[x]=++cnt;id[cnt]=x;size[x]=1;dep[x]=dep[fa[x][0]]+1;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]){fa[en[i]][0]=x;dfs(en[i]);size[x]+=size[en[i]];} } void make(int v,int l,int r) {ss[v].clear();if(l==r){ss[v].push_back(w[id[l]]);return;}int mid=l+r>>1,ls=v<<1,rs=ls|1;make(ls,l,mid);make(rs,mid+1,r);int i=0,ni=ss[ls].size()-1;int j=0,nj=ss[rs].size()-1;while(i<=ni && j<=nj) ss[v].push_back(ss[ls][i]<ss[rs][j]?ss[ls][i++]:ss[rs][j++]);while(i<=ni) ss[v].push_back(ss[ls][i++]);while(j<=nj) ss[v].push_back(ss[rs][j++]); } int find(int v,int l,int r) {if(qx<=l && r<=qy) return ss[v].size()-(upper_bound(ss[v].begin(),ss[v].end()--,qz)-ss[v].begin());int mid=l+r>>1,s=0;if(qx<=mid) s=find(v<<1,l,mid);if(qy>mid) s+=find(v<<1|1,mid+1,r);return s; } void dfs1(int x) {size[x]=1;dfn[x]=++cnt;id[cnt]=x;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]){dfs(en[i]);size[x]+=size[en[i]];} } inline void rebuild() {cnt=num=0;dfs1(1);make(1,1,n);cnt=n; } inline bool belong(int x,int y) {if(dep[x]<dep[y]) return false;for(int i=log2(dep[x]);i>=0;i--)if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];return x==y; } int main() {n=read();for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}for(int i=1;i<=n;i++) w[i]=read();dfs(1);cnt=n;for(int j=1;j<16;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];make(1,1,n);int m=read();lim=ceil(sqrt(m)*5);while(m--){int op=read(),x=read()^last,y=read()^last;if(op==0){if(x<=cnt){qx=dfn[x],qy=dfn[x]+size[x]-1,qz=y;last=find(1,1,cnt);}else last=0;for(int i=1;i<=num;i++)if(q[i].op==1){if((q[i].y<y)^(q[i].z<y) && belong(q[i].x,x)) last+=q[i].z>y?1:-1;}else{if(q[i].z>y && belong(q[i].x,x)) last++;}write(last),putchar('\n');}elseif(op==1){q[++num]=(data){1,x,w[x],y};w[x]=y;if(num==lim) rebuild();}else{q[++num]=(data){2,++n,x,y};insert(x,n);insert(n,x);fa[n][0]=x;dep[n]=dep[x]+1;w[n]=y;for(int i=1;i<16;i++) fa[n][i]=fa[fa[n][i-1]][i-1];if(num==lim) rebuild();}}return 0; }

總結

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

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