这道题与模板之间,多了个确定哪个为根的操作;

这道题有技巧,并不需要真正去建立以某个节点为根的树

关于路径的操作,无论以哪个点为根,得出的答案无影响;

关于对子节点进行操作的,有几种情况,

当查询节点刚好是根节点的话,就直接从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)的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  2. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  3. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  4. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  5. 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)

    题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...

  6. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  7. bzoj2243树链剖分+染色段数

    终于做了一道不是一眼出思路的代码题(⊙o⊙) 之前没有接触过这种关于染色段数的题目(其实上课好像讲过),于是百度了一下(现在思维能力好弱) 实际上每一段有用的信息就是总共有几段和两段各是什么颜色,在开 ...

  8. bzoj3631树链剖分

    虽然是水题1A的感觉太爽了O(∩_∩)O~ 题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值 本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查 前缀 ...

  9. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  10. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

随机推荐

  1. 牛客练习赛53 C题bitset

    题目链接https://ac.nowcoder.com/acm/contest/1114/C #include<bits/stdc++.h> using namespace std; #d ...

  2. 简单理解Linux系统的挂载是什么鬼

    转载自http://c.biancheng.net/view/2859.html Linux系统中“一切皆文件”,所有文件都放置在以根目录为树根的树形目录结构中.在 Linux 看来,任何硬件设备也都 ...

  3. Nginx配置服务器宕机策略

    Nginx解决服务器宕机问题,Nginx配置服务器宕机策略,如果服务器宕机,会找下一台机器进行访问        配置nginx.cfg配置文件,在映射拦截地址中加入代理地址响应方案 location ...

  4. 解决VMware中Ubuntu18.04全屏问题

    在VMware中Ubuntu18.04全屏问题   在虚拟机机中安装完Ubuntu18.04之后界面显示的特别小,默认的好像是800*600分辨率,看着不舒服.先是在设置->设备->显示 ...

  5. AspxDashboardView 更新参数

    AspxDashboardView 更新参数 function SetThrendDashboardView() { console.log("就是这样被你征服"); var to ...

  6. [CodeIgniter4]故障排除和本地开发服务器

    故障排除 以下是一些常见的安装问题,以及建议的解决方法. 我必须在我的URL中包含index.php 如果``/mypage/find/apple``类似的URL``/index.php/mypage ...

  7. oracle 锁表处理

    1.查询 select object_name,machine,s.sid,s.serial#from v$locked_object l,dba_objects o ,v$session swher ...

  8. Weighted Visibility Graph With Complex Network Features in the Detection of Epilepsy

    Their data five data set, 100 single channel of EEG signals, each channel EEG has 4097 data point. t ...

  9. Python列表和字典的简单实操例子

    # coding=utf-8 name_l = [] passwd_l = [] money_l = [] goods = {} index = 0 def input_user(): print(& ...

  10. HTML的创建

    创建一个HTML 直到产生scr文件之前的创建和原来建Java项目一样. 把scr文件Delete. 创建HTML File 4. 设置浏览器(我用的是搜狗浏览器,所以先找到搜狗的exe文件位置,导入 ...