树链剖分 (ZQU1607)
这道题与模板之间,多了个确定哪个为根的操作;
这道题有技巧,并不需要真正去建立以某个节点为根的树
关于路径的操作,无论以哪个点为根,得出的答案无影响;
关于对子节点进行操作的,有几种情况,
当查询节点刚好是根节点的话,就直接从1开始遍历就好 (因为这道题是以1为根节点)
当查询的节点的孩子或孙子中包括根节点的话,则需要用根节点得出的值去剪掉这个根节点得出的值
(这里以查询作为例子,更新值也是同样的道理)
所以,整个代码中跟模板的区别是,多了一步 确定查询节点跟根节点关系的代码 (代码中的函数名为work2)
- #include<algorithm>
- #include<iostream>
- #include<cstdlib>
- #include<cstring>
- #include<cstdio>
- #define Rint register int
- #define mem(a,b) memset(a,(b),sizeof(a))
- #define Temp template<typename T>
- using namespace std;
- typedef long long ll;
- #define mid ((l+r)>>1)
- #define lson rt<<1,l,mid
- #define rson rt<<1|1,mid+1,r
- #define len (r-l+1)
- ll root,n; //n需要作为全局变量
- const ll maxn=+;
- //见题意
- ll e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
- //链式前向星数组,w[]、wt[]初始点权数组
- ll a[maxn<<],laz[maxn<<];
- //线段树数组、lazy操作
- ll son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
- //son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点
- ll res=;
- //查询答案
- inline void add(ll x,ll y){//链式前向星加边
- to[++e]=y;
- nex[e]=beg[x];
- beg[x]=e;
- }
- //-------------------------------------- 以下为线段树
- inline void pushdown(ll rt,ll lenn){
- laz[rt<<]+=laz[rt];
- laz[rt<<|]+=laz[rt];
- a[rt<<]+=laz[rt]*(lenn-(lenn>>));
- a[rt<<|]+=laz[rt]*(lenn>>);
- // a[rt<<1]%=mod;
- // a[rt<<1|1]%=mod;
- laz[rt]=;
- }
- inline void build(ll rt,ll l,ll r){
- if(l==r){
- a[rt]=wt[l];
- // if(a[rt]>mod)a[rt]%=mod;
- return;
- }
- build(lson);
- build(rson);
- a[rt]=a[rt<<]+a[rt<<|];
- }
- inline void query(ll rt,ll l,ll r,ll L,ll R){
- if(L<=l&&r<=R){res+=a[rt];return;}
- else{
- if(laz[rt])pushdown(rt,len);
- if(L<=mid)query(lson,L,R);
- if(R>mid)query(rson,L,R);
- }
- }
- inline void update(ll rt,ll l,ll r,ll L,ll R,ll k){
- if(L<=l&&r<=R){
- laz[rt]+=k;
- a[rt]+=k*len;
- }
- else{
- if(laz[rt])pushdown(rt,len);
- if(L<=mid)update(lson,L,R,k);
- if(R>mid)update(rson,L,R,k);
- a[rt]=a[rt<<]+a[rt<<|];
- }
- }
- //---------------------------------以上为线段树
- inline ll qRange(ll x,ll y){
- ll ans=;
- while(top[x]!=top[y]){//当两个点不在同一条链上
- if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
- res=;
- query(,,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
- ans+=res;
- // ans%=mod;//按题意取模
- x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
- }
- //直到两个点处于一条链上
- if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
- res=;
- query(,,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
- ans+=res;
- return ans;
- }
- inline void updRange(ll x,ll y,ll k){//同上
- //k%=mod;
- while(top[x]!=top[y]){
- if(dep[top[x]]<dep[top[y]])swap(x,y);
- update(,,n,id[top[x]],id[x],k);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y])swap(x,y);
- update(,,n,id[x],id[y],k);
- }
- inline ll qSon(ll x){
- res=;
- query(,,n,id[x],id[x]+siz[x]-);//子树区间右端点为id[x]+siz[x]-1
- return res;
- }
- inline void updSon(ll x,ll k){//同上
- update(,,n,id[x],id[x]+siz[x]-,k);
- }
- inline void dfs1(ll x,ll f,ll deep){//x当前节点,f父亲,deep深度
- dep[x]=deep;//标记每个点的深度
- fa[x]=f;//标记每个点的父亲
- siz[x]=;//标记每个非叶子节点的子树大小
- ll maxson=-;//记录重儿子的儿子数
- for(ll i=beg[x];i;i=nex[i]){
- ll y=to[i];
- if(y==f)continue;//若为父亲则continue
- dfs1(y,x,deep+);//dfs其儿子
- siz[x]+=siz[y];//把它的儿子数加到它身上
- if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号
- }
- }
- inline void dfs2(ll x,ll topf){//x当前节点,topf当前链的最顶端的节点
- id[x]=++cnt;//标记每个点的新编号
- wt[cnt]=w[x];//把每个点的初始值赋到新编号上来
- top[x]=topf;//这个点所在链的顶端
- if(!son[x])return;//如果没有儿子则返回
- dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理
- for(ll i=beg[x];i;i=nex[i]){
- ll y=to[i];
- if(y==fa[x]||y==son[x])continue;
- dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链
- }
- }
- ll check2(ll xx,ll yy){
- ll rt=xx,lst=yy;
- while(top[xx]!=top[yy]){
- if(dep[top[xx]]<dep[top[yy]]) swap(xx,yy);
- lst=top[xx];xx=fa[top[xx]];
- }
- if(dep[xx]>dep[yy]) swap(xx,yy);
- if(xx!=rt) return ; //如果得出的点不是等于查询节点
- //则说明没有关系,这里举个例子,比如在一个树中,他的父亲节点是根节点,
- //那么就没有关系;换一个说法(如果yy不是xx的子树,则没有影响)
- //两个节点没有关系,return 0
- if(fa[lst]==xx) return lst; //如果lst的父亲是这个查询节点,则根节点
- //便是这个lst;
- return son[xx]; //可以说return son[xx]是最难理解的了。
- } //不过还是理解了,开心! 如果fa[lst]的节点是查询节点的子节点或者孙节点;
- //那么从他重儿子以下的点都是不在查询范围(更新范围)的,这里画图模拟一遍
- //就会发现就是这么个道理。
- int main()
- {
- scanf("%lld",&n);
- for(ll i=;i<=n;i++) scanf("%lld",&w[i]);
- for(ll i=;i<=n;i++){
- ll t;
- scanf("%lld",&t);
- add(t,i);add(i,t);
- }
- ll m;
- scanf("%lld",&m);
- dfs1(,,);
- dfs2(,);
- build(,,n);
- root=;
- while(m--){
- ll k,x,y,z;
- scanf("%lld",&k);
- if(k==){
- scanf("%lld",&root);
- }
- if(k==){
- scanf("%lld%lld%lld",&x,&y,&z);
- updRange(x,y,z);
- }
- if(k==){
- scanf("%lld%lld",&x,&z);
- if(x==root) {updSon(,z);continue;}
- y=check2(x,root);
- if(y==) updSon(x,z);
- else{
- updSon(,z);
- updSon(y,-z);
- }
- }
- if(k==){
- scanf("%lld%lld",&x,&y);
- printf("%lld\n",qRange(x,y));
- }
- if(k==){
- scanf("%lld",&x);
- if(x==root){
- printf("%lld\n",qSon());
- continue;
- }
- y=check2(x,root);
- if(y==) printf("%lld\n",qSon(x));
- else{
- printf("%lld\n",qSon()-qSon(y));
- }
- }
- }
- return ;
- }
树链剖分 (ZQU1607)的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- bzoj2243树链剖分+染色段数
终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...
- bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
随机推荐
- ZDialog关闭父窗口、往父窗口传值、刷新父窗口
关闭自己 //关闭自己 top.Dialog.close(); 关闭父窗口 //关闭父窗口 parentDialog.parentWindow.close() 往父窗口传值 //在本页面,调用父页面方 ...
- 题解【AcWing883】高斯消元解线性方程组
题面 高斯消元模板题. 这里直接讲述一下高斯消元的算法流程: 枚举每一列 \(c\): 找到第 \(c\) 列绝对值最大的一行: 将这一行换到最上面: 将该行的第一个数变成 \(1\): 将下面所有行 ...
- springboot 扫描不到包 @SpringBootApplication 自动配置原理
解决方案 在main类中增加注解 @ComponentScan("com.test.test.*") 扫描具体的包 @ComponentScan(basePackages = {& ...
- [转]JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释
jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分: ...
- 占位 LR
占位 LR include: LR403
- <if test="type == '0' ">没有进去这个判断的问题
在MyBatis的mapp文件中的if判断中是这样写的 <if test="type == '0' "> and so1.id = #{unitcode} </i ...
- 颜色color转为rgb格式
function convertHexToRGB(color) { if (color.length === 4) { let extendedColor = &q ...
- C++-POJ2975-Nim
题目把Nim游戏为什么可以取异或和讲解得十分清楚,建议多读几次,理解一下 再一个,可以把每次异或视为一次取数,因此(k[i]^sg)<k[i]即为一种可行操作 /* Nim is a 2-pla ...
- x = cos x 的解析形式
x = cos x 的解析形式 玩计算器的发现 大家都玩过计算器吧, 不知注意到没有. 输入任意数, 然后不断按最后总会输出. 什么, 你说明明记得是:? 哦, 因为你用了角度制. 这一系列操作等价于 ...
- windows10中docker nginx开启 但页面访问不了
Windows下对docker端口进行映射,但是当你在主机的浏览器中,打开localhost:port无法访问对应的服务. docker是运行在Linux上的,在Windows中运行docker,实际 ...