题意:

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&#39;s Story(树链剖分+树状数组/线段树)

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

  2. Aragorn&#39;s Story 树链剖分+线段树 &amp;&amp; 树链剖分+树状数组

    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&#39;s Story 树链剖分+树状数组 或 树链剖分+线段树

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

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

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

  6. HDU 3966 Aragorn&#39;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. System.Security.Cryptography.CryptographicException,密钥集不存在

    非常感谢,已经解决了.是当前用户没有权限访问证书的私钥文件的问题,之前尝试去解决,但是在对:C:\Documents and Settings\All Users\Application Data\M ...

  2. Vue基础理论

    一 vue的定位 (1)Vue.js是一个构建数据驱动的 web 界面的库. (2)Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. (3)Vue.js 自身不是一 ...

  3. 【Flex学习】Flex4学习网站

    http://blog.minidx.com/category/flex  来自为知笔记(Wiz)

  4. mysql查询今天、昨天、7天、近30天、本月、上一月 数据

    今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...

  5. Android高效内存1:一张图片占用多少内存

    在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用.而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果.本文就简单介绍一张图片到 ...

  6. JaveScript用二分法与普通遍历(冒泡)

    二分法 查找 概念: 从有序的数列中,折半查找. 思路: --> 找到数组中最中间的元素,将其作为基准 --> 从0开始判断数组中的元素,与基准进行比较 --> 比基准小的元素,存入 ...

  7. Windows 2008 r2上安装MySQL

    用MSI安装包安装 根据自己的操作系统下载对应的32位或64位安装包.按如下步骤操作: MySQL数据库官网的下载地址http://dev.mysql.com/downloads/mysql,第一步: ...

  8. line-height的高度机理

    1.元素高度从何而来?是由里面的文字撑开的? <!DOCTYPE html> <html lang="en"> <head> <meta ...

  9. &#39;An instance 0x155e74a0 of class UIWebView was deallocated while key value observers were still registered with it.

    在iOS和html混编的时候,当用iOS原生的navigation导航pop回去的时候,出现 *** Terminating app due to uncaught exception 'NSInte ...

  10. cloudstack ssvm 管理地址不够造成无法启动修复过程

    cloudstack日志记录: 上面已经提示了,管理ip没有了,造成这个原因很多,遇到过ssvm非正常关闭就有可能不释放IP慢慢把IP消耗掉.总之这肯定是BUG.按照上面的提示找到对应pod 和dc ...