欢迎访问 生活随笔!

生活随笔

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

编程问答

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

发布时间:2025/3/15 编程问答 37 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 n5n

  • 还有就是打线段树询问时: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的妹子树的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。