树链刨分(class版)
class版树链剖(刨)分
感谢沙华大佬的赞助
其实没什么太大变化,就是用了几次一顿乱指。。。
CODE:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define pushup(rt) t[rt].data=(t[ls].data+t[rs].data)%mod
#define N 100005
using namespace std;
int n,m,mod,tot,res;
int top[N],cnt,w[N],wt[N],head[N];
int fa[N],deep[N],idx[N],son[N],size[N];
class subdivision {
private:
struct edge {
int next,to;
}e[(N<<1)];
private:
struct segtree {
int data,left,right,tag;
inline int len() { return right - left + 1; }
}t[(N<<2)];
public:
inline void edge_build(int u,int v) {
e[++tot].to = v;
e[tot].next = head[u];
head[u] = tot;
return ;
}
public:
inline void tree_build(int rt , int l , int r){
t[rt].left = l;
t[rt].right = r;
t[rt].tag = 0;
if(l == r) {
t[rt].data = wt[l];
return ;
}
tree_build(ls,l,mid);
tree_build(rs,mid +1,r);
pushup(rt);
return ;
}
private:
inline void pushdown(int rt) {
t[ls].tag = (t[ls].tag + t[rt].tag) % mod;
t[rs].tag = (t[rs].tag + t[rt].tag) % mod;
t[ls].data = (t[ls].data + t[rt].tag * t[ls].len() ) % mod;
t[rs].data = (t[rs].data + t[rt].tag * t[rs].len() ) % mod;
t[rt].tag = 0;
return ;
}
public:
inline void update(int rt , int ll , int rr , int w) {
int l = t[rt].left;
int r = t[rt].right;
if(ll <= l && r <= rr) {
t[rt].tag += w;
t[rt].data = (t[rt].data + t[rt].len() * w) % mod;
return ;
}
if(t[rt].tag) pushdown(rt);
if(ll <= mid) update(ls,ll,rr,w);
if(rr > mid) update(rs,ll,rr,w);
pushup(rt);
return ;
}
public:
inline void query(int rt,int ll,int rr) {
int l = t[rt].left;
int r = t[rt].right;
if(ll <= l && r <= rr) {
res += t[rt].data;
return ;
}
if(t[rt].tag) pushdown(rt);
if(ll <= mid) query(ls,ll,rr);
if(rr > mid) query(rs,ll,rr);
return ;
}
public:
inline void dfs1(int now,int f,int dep) {
deep[now] = dep;
fa[now] = f;
size[now] = 1;
int maxson = -1;
for(int i = head[now] ; i ; i = e[i].next) {
int y = e[i].to;
if(y == f) continue;
dfs1(y , now , dep + 1);
size[now] += size[y];
if(size[y] > maxson) {
son[now] = y;
maxson = size[y];
}
}
return ;
}
public:
inline void dfs2(int now,int topf) {
idx[now] = ++cnt;
wt[cnt] = w[now];
top[now] = topf;
if(!son[now]) return ;
dfs2(son[now],topf);
for(int i = head[now] ; i ; i = e[i].next) {
int y = e[i].to;
if(y == fa[now] || y == son[now]) continue;
dfs2(y,y);
}
return ;
}
public:
inline int qrange(int x,int y) {
int ans = 0;
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x,y);
res = 0;
query(1 , idx[top[x]] , idx[x]);
ans = (ans + res) % mod;
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
res = 0;
query(1 , idx[x] , idx[y]);
return (ans + res) % mod;
}
public:
inline void uprange(int x,int y,int k) {
k %= mod;
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x,y);
update(1 , idx[top[x]] , idx[x],k);
x = fa[top[x]];
}
if(deep[x] > deep[y]) swap(x,y);
update(1 , idx[x] , idx[y] , k);
return ;
}
};
subdivision *s;
int main(){
int root,a,b;
scanf("%d%d%d%d",&n,&m,&root,&mod);
for(int i = 1 ; i <= n ; ++i)
scanf("%d",&w[i]);
for(int i = 1 ; i < n ; ++i){
scanf("%d%d",&a,&b);
s->edge_build(a,b);
s->edge_build(b,a);
}
s->dfs1(root,0,1);
s->dfs2(root,root);
s->tree_build(1,1,n);
int k,x,y,z;
while(m--) {
scanf("%d%d",&k,&x);
if(k == 1) {
scanf("%d%d",&y,&z);
s->uprange(x,y,z);
}
if(k == 2) {
scanf("%d",&y);
printf("%d\n",s->qrange(x,y) );
}
if(k == 3) {
scanf("%d",&z);
s->update(1 , idx[x] , idx[x] + size[x]-1,z);
}
if(k == 4) {
res = 0;
s->query(1 , idx[x] , idx[x] + size[x]-1);
printf("%d\n",res % mod);
}
}
return 0;
}
树链刨分(class版)的更多相关文章
- xcoj 1103 插线板(树链刨分求最大子段和)
1103: 插线板 时间限制: 1 Sec 内存限制: 128 MB提交: 14 解决: 7 标签提交统计讨论版EditTestData 题目描述 从前有一堆古老的插线板,任意两个插线板之间只有一 ...
- bzoj 5210(树链刨分下做个dp)
5210: 最大连通子块和 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 211 Solved: 65[Submit][Status][Discus ...
- hdu 5452(树链刨分)
看到题目,想了挺长时间,发现不会,然后看着样子像是树上成段操作,所以查了下树链刨分,结果真的就是这个东西... Minimum Cut Time Limit: 3000/2000 MS (Java/O ...
- HDU - 3966 树链刨分
题目传送门 操作就是询问某个点的值, 然后就是对一条路径上的值全部修改. 最基本的树刨题目了. 树刨的思想: 1. 对于每个点找到他的重儿子. void dfs1(int o, int u){ sz[ ...
- POJ 2763 Housewife Wind 树链拋分
一.前言 这破题WA了一天,最后重构还是WA,最后通过POJ讨论版得到的数据显示,我看上去是把某个变量写错了..于是,还是低级错误背锅啊....代码能力有待进一步提升2333333 二.题意 某家庭主 ...
- HDU 3966 Aragorn's Story 树链拋分
一.写在前面 终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作.经历了若干长时间之后终于打了出来(为什么每次学什么东西都 ...
- P3565 由简单的树形dp 引入 长链刨分
这道题感觉不太行 因为自己没想出来. 先说一下暴力吧,取三个点 让两两之间的距离相等怎么做呢,看起来是很复杂的样子的,但是仔细观察发现 答案出自一个点的儿子之间 或者儿子和父亲之间. 暴力枚举三个点然 ...
- hdu 3804树链剖分+离线操作
/* 树链刨分+离线操作 题意:给你一棵树,和询问x,y 从节点x--节点1的小于等于y的最大值. 解:先建一个空树,将树的边权值从小到大排序,将询问y按从小到大排序 对于每次询问y将小于等于y的边权 ...
- spoj 375 树链剖分模板
/* 只是一道树链刨分的入门题,作为模板用. */ #include<stdio.h> #include<string.h> #include<iostream> ...
随机推荐
- apache 运行一段时间出现错误
环境是win2008,apache 2.4.29 Win64 VC15,php 7.1.10(7.1.11).事件完整内容: “-------------------------- 错误应用程序名称: ...
- Elastic-Job-Lite 源码分析 —— 运维平台
本文基于 Elastic-Job V2.1.5 版本分享 1. 概述 2. Maven模块 elastic-job-common-restful 3. Maven模块 elastic-job-cons ...
- 循环取月的三位英语名 Jan Feb
CultureInfo ci = new CultureInfo("en-US"); DateTime now = DateTime.Now; for (int i = 0; i ...
- 洛谷 P2245 星际导航 解题报告
P2245 星际导航 题目描述 sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为了方便起见,我们可以认为宇宙是一张有N 个顶点和M 条边的带权无向 ...
- 解题:HNOI 2014 世界树
题面 首先建虚树 DFS求虚树上每个点所属的点和到它所属点的距离,然后在=考虑虚树所有的边(对应原树一条链).如果两个端点所属节点不同就倍增出分界点统计答案,否则不用管(之后会统计到的):注意根节点特 ...
- HDU 4280 ISAP+BFS 最大流 模板
Island Transport Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- 洛谷P1140 相似基因 (DP)
洛谷P1140 相似基因 题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了44种核苷酸,简记作A,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. ...
- 使用开源Breeze工具部署Kubernetes 1.12.1高可用集群
Breeze项目是深圳睿云智合所开源的Kubernetes图形化部署工具,大大简化了Kubernetes部署的步骤,其最大亮点在于支持全离线环境的部署,且不需要FQ获取Google的相应资源包,尤其适 ...
- null和System.DBNull.Value的区别
我记得之前在写一个程序的时候用到了这个知识点,当时判断的时候,有时候null可以,有时候必须是System.DBNull.Value 由于不清楚这两个的区别所以纠结了很久.查了一下,二者的区别如下: ...
- HDU 1730 类NIM模型
两者间的间距就是可取石子数,因为对于行内黑白相连的局面该子游戏已经结束了因为此时不管先手再怎么移都是必败,SG=0的终止态 /** @Date : 2017-10-14 21:46:21 * @Fil ...