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的妹子树相关推荐
- 块状树(bzoj 3720: Gty的妹子树)
问题概述: 一棵n个节点的树,每个节点都有一个权值,之后三种操作: ①0 u v查询以u点为根的子树中权值大于v的有多少个 ②1 u v表示将u点的权值修改为v ③2 u v表示新建一个节点,编号为节 ...
- 3720: Gty的妹子树
3720: Gty的妹子树 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1440 Solved: 482 [Submit][Status][Di ...
- #莫比乌斯反演#BZOJ 2671 洛谷 4466 和与积 Calc
题目 求有多少对(a,b)(a,b)(a,b)满足1≤a<b≤n1\leq a<b\leq n1≤a<b≤n且a+b∣aba+b|aba+b∣ab 分析 若gcd(a,b)=1gcd ...
- BZOJ 4385 洛谷3594 POI2015 WIL-Wilcze doły
[题解] 手残写错调了好久QAQ...... 洛谷的数据似乎比较水.. n个正整数!!这很重要 这道题是个类似two pointer的思想,外加一个单调队列维护当前区间内长度为d的子序列中元素之和的最 ...
- BZOJ 2733 | 洛谷 P3224 [HNOI2012]永无乡
https://www.lydsy.com/JudgeOnline/problem.php?id=2733 https://www.luogu.org/problemnew/show/P3224 C+ ...
- bzoj 2653 洛谷 P2839 [国家集训队] middle
2653: middle Time Limit: 20 Sec Memory Limit: 512 MB Submit: 2381 Solved: 1340 [Submit][Status][Di ...
- #距离#JZOJ 3256 BZOJ 3170 洛谷 3964 松鼠聚会
题目 分析 首先这个距离是切比雪夫距离,得把它转换成曼哈顿距离,也就是把(x,y)(x,y)(x,y)变成(x+y2,x−y2)(\frac{x+y}{2},\frac{x-y}{2})(2x+y, ...
- #快速幂,eratosthenes筛#bzoj 3930 洛谷 3172 选数
题目 从区间 [ l ∼ r ] [l\sim r] [l∼r]中选取 n n n个整数,总共有 ( r − l + 1 ) n (r-l+1)^n (r−l+1)n种方案.问最大公约数刚好为 k k ...
- bzoj 1296 洛谷4158 [SCOI2009]粉刷匠 题解
题意简述 一个 n × m n\times m n×m的矩阵,每个位置珂能是粉色(0表示)或者是蓝色(1表示),然后你珂以对同一行里连续一段长度的区间染上一种颜色(覆盖型),你能染 t t t次,每次 ...
最新文章
- ui设计和python哪个容易学_软件开发和ui设计那个容易学?
- 康普在金色一号中心缔造光纤新历史
- MySql DATE_FORMAT函数用法
- 自定义Spring命名空间使JAXB更容易
- php文件的作用,php入口文件的作用-PHP问题
- SQL 获取指定月份的天数
- HDU4706 Children's Day
- 如何创建ChromeApp
- 开课吧Java教程:如何用listFiles()方法
- asp.net中使用下拉菜单的级联问题
- 关于时间格式的解析问题
- 计算机系最好的985大学排名,2017年全国“985”大学排名及王牌专业全解析
- win11微软拼音输入法失效、没有候选框、不显示语言栏的问题
- web前端期末大作业:婚纱网页主题网站设计——唯一旅拍婚纱公司网站HTML+CSS+JavaScript
- 脑科学和人工智能的思考
- 用Python自制随机点名程序,压迫感来了~
- springboot 之 SpringBoot指定额外需要扫描的包
- linux 转换viso为pdf,foxpdf Visio转PDF转换器
- java不能连接mysql_java无法连接数据库问题(急)
- ArcGIS将太平洋调至地图中间(改变地图中心经度)