题意:

http://acm.hdu.edu.cn/showproblem.php?pid=3966

给一棵树,并给定各个点权的值,然后有3种操作:

I x y z : 把x到y的路径上的所有点权值加上z

D x y z:把x到y的路径上的所有点权值减去z

Q z:查询节点编号为x的权值

这里主要放下用树状数组维护的模板

区间修改单点查询 好像用线段树更好?

em.... 两种都放好了~

好像说hduoj是windows系统容易爆栈 手动扩栈加这句

#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <bits/stdc++.h>
using namespace std;
#define mem(i,j) memset(i,j,sizeof(i))
#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1 const int maxn = 5e4 + ;
const int maxnode = maxn<<; LL head[maxn], tot, pos;
LL fa[maxn], son[maxn], dep[maxn], num[maxn];
// i的父亲、i的重结点、i的深度、i的儿子个数
LL top[maxn], p[maxn], fp[maxn];
// i所在链的顶端、ID->dfsID、dfsID->ID
LL n,m,q;
LL val[maxn];
struct Edge { int to,ne; }e[maxnode];
void init() {
tot=; pos=;
mem(head,); mem(son,);
}
void add(int u,int v) {
e[tot].to = v;
e[tot].ne = head[u];
head[u] = tot++;
} struct IntervalTree {
LL _sum, _min, _max;
LL sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode], addv[maxnode];
void init() {
mem(sumv,); mem(setv,); mem(addv,);
} void maintain(int L, int R, int rt) {
int lc = rt<<, rc = rt<<|;
if(R > L) {
sumv[rt] = sumv[lc] + sumv[rc];
minv[rt] = min(minv[lc], minv[rc]);
maxv[rt] = max(maxv[lc], maxv[rc]);
}
if(setv[rt] >= ) {
minv[rt] = maxv[rt] = setv[rt];
sumv[rt] = setv[rt] * (R-L+);
}
if(addv[rt]) {
minv[rt] += addv[rt]; maxv[rt] += addv[rt];
sumv[rt] =sumv[rt]+addv[rt] * (R-L+);
}
} void pushdown(int rt) {
int lc = rt*, rc = rt*+;
if(setv[rt] >= ) {
setv[lc] = setv[rc] = setv[rt];
addv[lc] = addv[rc] = ; setv[rt] = -;
}
if(addv[rt]) {
addv[lc] += addv[rt]; addv[rc] += addv[rt];
addv[rt] = ;
}
} ///update(更新区间左右端点、更新值、更新选项 op=1为加减 op!=1为置值、当前区间左右端点、根)
void update(int L, int R, LL v, int op, int l, int r, int rt){
//int lc = rt<<1, rc = rt<<1|1;
if(L <= l && R >= r) {
if(op == ) addv[rt] += v;
else { setv[rt] = v; addv[rt] = ; }
} else {
pushdown(rt);
int m = l + (r-l)/;
if(L <= m) update(L, R, v, op, lson);
else maintain(lson);
if(R > m) update(L, R, v, op, rson);
else maintain(rson);
}
maintain(l, r, rt);
} ///query(问询的左右端点、累加lazy_tag的累加量、当前区间左右端点、根)
void query(int L, int R, LL add, int l, int r, int rt) {
if(setv[rt] >= ) {
LL v = setv[rt] + add + addv[rt];
_sum += v * (LL)(min(r,R)-max(l,L)+);
_min = min(_min, v);
_max = max(_max, v);
} else if(L <= l && R >= r) {
_sum += sumv[rt] + add * (LL)(r-l+);
_min = min(_min, minv[rt] + add);
_max = max(_max, maxv[rt] + add);
} else {
int m = l + (r-l)/;
if(L <= m) query(L, R, add+addv[rt], lson);
if(R > m) query(L, R, add+addv[rt], rson);
}
}
}T; /** -----树链剖分----- */ void dfs1(int u,int pre,int d) {
dep[u]=d; fa[u]=pre; num[u]=;
for(int i=head[u];i;i=e[i].ne) {
int v=e[i].to;
if(v!=fa[u]) {
dfs1(v,u,d+); num[u]+=num[v];
if(!son[u] || num[v]>num[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int sp) {
top[u]=sp; p[u]=++pos; fp[p[u]]=u;
if(!son[u]) return; dfs2(son[u],sp);
for(int i=head[u];i;i=e[i].ne) {
int v=e[i].to;
if(v!=son[u] && v!=fa[u]) dfs2(v,v);
}
}
// 查询树上x到y的总和
LL queryPath(int x,int y) {
LL ans=0LL;
int fx=top[x], fy=top[y];
// fx==fy 说明到了LCA
while(fx!=fy) { // x y不在同一条重链上
if(dep[fx]>=dep[fy]) {
T._sum=0LL; T.query(p[fx],p[x],,,pos,);
ans=(ans+T._sum)%mod;
x=fa[fx];
} else {
T._sum=0LL; T.query(p[fy],p[y],,,pos,);
ans=(ans+T._sum)%mod;
y=fa[fy];
} // 先加离LCA更远的 且只加到父亲节点的一段 一步步移
fx=top[x], fy=top[y];
} // 直到两点在同一条重链上跳出 此时节点必连续 // 将最后到达LCA的一段连续的区间加上
if(p[x]>p[y]) swap(x,y);
T._sum=0LL; T.query(p[x],p[y],,,n,); return (ans+T._sum)%mod;
}
// 将树上x到y都加上z (和queryPath()差不多)
void updatePath(LL x,LL y,LL z) {
int fx=top[x], fy=top[y];
while(fx!=fy) {
if(dep[fx]>=dep[fy]) {
T.update(p[fx],p[x],z,,,n,);
x=fa[fx];
} else {
T.update(p[fy],p[y],z,,,n,);
y=fa[fy];
}
fx=top[x], fy=top[y];
} if(p[x]>p[y]) swap(x,y);
T.update(p[x],p[y],z,,,n,);
} /** ---------------- */ int main()
{
while(~scanf("%lld%lld%lld",&n,&m,&q)) {
init();
for(int i=;i<=n;i++)
scanf("%lld",&val[i]);
for(int i=;i<m;i++) {
int a,b; scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
dfs1(,,); // 根节点 前驱节点 深度
dfs2(,); // 当前节点 起始重结点
T.init();
for(int i=;i<=n;i++)
T.update(p[i],p[i],val[fp[p[i]]],,,n,); while(q--) {
LL x,y,z; char op;
scanf(" %c",&op); //printf("op%d\n",op);
if(op=='Q') {
scanf("%lld",&x);
T._sum=; T.query(p[x],p[x],0LL,,n,);
printf("%lld\n",T._sum);
} else {
scanf("%lld%lld%lld",&x,&y,&z);
if(op=='D') z=-z;
updatePath(x,y,z);
}
}
} return ;
} 线段树

线段树

#include <bits/stdc++.h>
using namespace std;
#define mem(i,j) memset(i,j,sizeof(i))
#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1 const int maxn = 5e4 + ;
const int maxnode = maxn<<;
const int maxedge = maxn<<; LL head[maxn], tot, pos;
LL fa[maxn], son[maxn], dep[maxn], num[maxn];
// i的父亲、i的重结点、i的深度、i的儿子个数
LL top[maxn], p[maxn], fp[maxn];
// i所在链的顶端、ID->dfsID、dfsID->ID
LL n,m,q;
LL val[maxn];
struct Edge { int to,ne; }e[maxedge];
void init() {
tot=; mem(head,);
pos=; mem(son,);
}
void add(int u,int v) {
e[tot].to = v;
e[tot].ne = head[u];
head[u] = tot++;
} struct Tree {
int N;
LL sumT[maxn];
void init() {
N=;
while(N<=n) N<<=;
mem(sumT,);
}
int lowbit(int i) { return -i&i; }
void add(int i,LL x) {
while(i<=N) {
sumT[i]+=x;
i+=lowbit(i);
}
}
LL sum(int i) {
LL res=0LL;
while(i) {
res+=sumT[i];
i-=lowbit(i);
} return res;
}
}T; /** -----树链剖分----- */ void dfs1(int u,int pre,int d) {
dep[u]=d; fa[u]=pre; num[u]=;
for(int i=head[u];i;i=e[i].ne) {
int v=e[i].to;
if(v!=fa[u]) {
dfs1(v,u,d+); num[u]+=num[v];
if(!son[u] || num[v]>num[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int sp) {
top[u]=sp; p[u]=++pos; fp[p[u]]=u;
if(!son[u]) return; dfs2(son[u],sp);
for(int i=head[u];i;i=e[i].ne) {
int v=e[i].to;
if(v!=son[u] && v!=fa[u]) dfs2(v,v);
}
}
// 将树上x到y都加上z (和queryPath()差不多)
void updatePath(LL x,LL y,LL z) {
int fx=top[x], fy=top[y];
while(fx!=fy) {
if(dep[fx]>=dep[fy]) {
T.add(p[fx],z); T.add(p[x]+,-z);
x=fa[fx];
} else {
T.add(p[fy],z); T.add(p[y]+,-z);
y=fa[fy];
}
fx=top[x], fy=top[y];
} if(p[x]>p[y]) swap(x,y);
T.add(p[x],z); T.add(p[y]+,-z);
} /** ---------------- */ int main()
{
while(~scanf("%lld%lld%lld",&n,&m,&q)) {
init();
for(int i=;i<=n;i++)
scanf("%lld",&val[i]);
for(int i=;i<m;i++) {
int a,b; scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
dfs1(,,); // 根节点 前驱节点 深度
dfs2(,); // 当前节点 起始重结点
T.init();
for(int i=;i<=n;i++)
T.add(p[i],val[i]),
T.add(p[i]+,-val[i]); while(q--) {
LL x,y,z; char op;
scanf(" %c",&op);
if(op=='Q') {
scanf("%lld",&x);
printf("%lld\n",T.sum(p[x]));
} else {
scanf("%lld%lld%lld",&x,&y,&z);
if(op=='D') z=-z;
updatePath(x,y,z);
}
}
} return ;
}

树状数组

HDU 3966 /// 树链剖分+树状数组的更多相关文章

  1. hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...

  2. Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

    Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

  3. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  4. HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树

    HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...

  5. hdu 3966 Aragorn&#39;s Story(树链剖分+树状数组)

    pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...

  6. HDU 3966 Aragorn's Story (树链剖分+树状数组)

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  7. HDU 5044 (树链剖分+树状数组+点/边改查)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...

  8. HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp

    传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...

  9. bzoj1146整体二分+树链剖分+树状数组

    其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include<cstdio> #include<cstr ...

随机推荐

  1. 可持化永久树 的 STL ( rope )

    rope 的基本操作 #include <ext/rope> using namespace __gnu_cxx; ]; rope<int> x; rope<int> ...

  2. [Go语言]cgo用法演示

        经历了数十年发展的C语言,各种各样的现成的库已经非常丰富.通过cgo,可以在Go语言中使用C语言代码,充分利用好现有的“轮子”. 本文所有代码,在下述环境中调试通过: Windows 8.1 ...

  3. 配置Maven私服

    Nexus 是“开箱即用”的系统,不需要数据库,它使用文件系统加 Lucene 来组织数据,支持 WebDAV 与 LDAP 安全身份认证.Nexus 还提供了强大的仓库管理功能,构件搜索功能,它基于 ...

  4. 1、Monkey环境搭建

    步骤: 1.下载adb压缩包: 32位计算机,用这个包:64位计算机,用这个包: 2.把对应的adb压缩包在本地解压,然后把解压后的文件里面的文件夹拷贝到D盘(当然随便你放在哪个目录)根目录,注意路径 ...

  5. 2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

    K-th Closest Distance 题目传送门 解题思路 二分答案+主席树 先建主席树,然后二分答案mid,在l和r的区间内查询[p-mid, p+mid]的范围内的数的个数,如果大于k则说明 ...

  6. mybatis执行test07测试类却显示test05测试类调用的sql语句出错

    1.测试类 @Test public void test07() { IStudentDao studentDao = new IStudentDaoImpl(); Student student = ...

  7. Tomcat集群session复制与Oracle的坑。。

    问题描述 公司某个系统使用了tomcat自带的集群session复制功能,然后后报了一个oracle驱动包里面的连接不能被序列化的异常. 01-Nov-2017 16:45:26.653 SEVERE ...

  8. leetcode.字符串.242有效的字母异位词-Java

    1. 具体题目 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词. 注:判断两个字符串包含的字母是否完全一样. 示例 1: 输入: s = "anagram&q ...

  9. JAVA集合--Iterator接口

        本文首发于cartoon的博客     转载请注明出处:https://cartoonyu.github.io/cartoon-blog     上一篇文章中我在集合元素的遍历中已经有涉及到I ...

  10. composer 的安装以及一些插件的下载等

    安装composer: 下载composer: curl -sS https://getcomposer.org/installer | php 将composer.phar文件移动到bin目录以便全 ...