HDU 3966 /// 树链剖分+树状数组
题意:
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 /// 树链剖分+树状数组的更多相关文章
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组)
pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...
- HDU 3966 Aragorn's Story (树链剖分+树状数组)
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 5044 (树链剖分+树状数组+点/边改查)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...
- HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp
传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...
- bzoj1146整体二分+树链剖分+树状数组
其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include<cstdio> #include<cstr ...
随机推荐
- es批量索引
使用Python操作Elasticsearch数据索引的教程 这篇文章主要介绍了使用Python操作Elasticsearch数据索引的教程,Elasticsearch处理数据索引非常高效,要的朋友可 ...
- UDP 两种丢包处理策略:丢包重传(ARQ) 和 前向纠错(FEC)
目录 1. 两种丢包处理策略 2. 前向纠错(FEC) 3. 丢包重传(ARQ) [参考文献] 1. 两种丢包处理策略 为了保证实时性,通常适应UDP协议来针对RTP数据进行传输,而UDP无法保证数据 ...
- 在命令行中运行Hadoop自带的WordCount程序
1.启动所有的线程服务 start-all.sh 记得要查看线程是否启动 jps 2.在根目录创建 wordcount.txt 文件 放置一些数据 3.创建 hdfs dfs -mkdir /文件夹 ...
- JUC源码分析-集合篇(六)LinkedBlockingQueue
JUC源码分析-集合篇(六)LinkedBlockingQueue 1. 数据结构 LinkedBlockingQueue 和 ConcurrentLinkedQueue 一样都是由 head 节点和 ...
- 9-MySQL-Ubuntu-数据表中数据的修改(二)
数据的修改(update) (1)修改整个字段: update 表名 set 字段1=值1,字段2=值2; (2)修改字段部分数据 update 表名 set 字段1=值1,字段2=值2,... wh ...
- [BOI2009]Radio Transmission 无线传输
题目描述 给你一个字符串,它是由某个字符串不断自我连接形成的. 但是这个字符串是不确定的,现在只想知道它的最短长度是多少. 输入输出格式 输入格式: 第一行给出字符串的长度,1 < L ≤ 1, ...
- hdu6290奢侈的旅行
高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏.在这个游戏的世界地图中一共有n个城镇,编号依次为1到n. 这些城镇之间有m条单向道路,第i 条单项道路包含四个参数ui,vi,ai,bi,表示一条 ...
- The J2EE Architecture
- .Net平台调用の初识
前言 工作过程中难免遇到混合编程,现在我们要谈的是C#和c++语言的编程.C#要调用C++的库目前可选主要有两种方式:Com技术和平台调用(P/Invoke).现在我们要谈的是P/Invoke技术. ...
- 加载ubuntu的时候卡在‘SMBus Host Controller not enabled'错误
实验系统:ubuntu-16.04.6-server-amd64 我在VMware安装完这个系统后进入发现卡在了’SMBus Host Controller not enabled‘里,后来查过网络发 ...