Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story
来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.php?pid=3966
这题就是一个模板题,模板调过了就可以过
#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define mid ((node[now].l+node[now].r)>>1)
#define lson node[now].l, mid, now<<1
#define rson mid+1, node[now].r, now<<1^1
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=;
const int INF=0x3f3f3f3f;
typedef int mint;
mint fa[N], siz[N], dep[N], son[N];
mint id[N], top[N], self[N], cnt;
/**
siz[u] 保存以u为根的子树节点个数
top[u] 保存当前节点所在链的顶端节点
son[u] 保存重儿子
dep[u] 保存结点u的深度值
fa[u] 保存结点u的父亲节点
id[u] 保存树中每个节点剖分以后的新编号(DFS的执行顺序)
self[u] 保存当前节点在树中的位置
**/
mint sz, head[N];
mint sav[N];
mint n, mod;
void read(int &x)
{
int f=;x=;char s=getchar();
while(s<''|s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
x*=f;
}
mint Max(mint a, mint b)
{ return a>b?a:b; }
mint Min(mint a, mint b)
{ return a<b?a:b; } struct Ed
{
int to, next;
}E[N*]; void insert_E(int u, int v)
{
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz++;
}
struct No
{
mint ret;
struct no
{
mint l, r, sum, mins, maxn, lazy, lazyset;
}node[N<<];
void build(int L, int R, int now)///建树
{
node[now].lazy=;
node[now].lazyset=;
node[now].l=L;
node[now].r=R;
if(L==R)
node[now].mins=node[now].maxn=node[now].sum=self[L];
else
{
build(L, mid, now<<);
build(mid+, R, now<<^);
pushup(now);
}
}
void pushup(int now)
{
node[now].sum=node[now<<].sum+node[now<<^].sum;
node[now].maxn=Max(node[now<<].maxn, node[now<<^].maxn);
node[now].mins=Min(node[now<<].mins, node[now<<^].mins);
}
void pushdown(int now)
{
if (node[now].lazy)
{
int len=node[now].r-node[now].l+;
node[now<<].lazy+=node[now].lazy;
node[now<<^].lazy+=node[now].lazy;
node[now<<].sum+=node[now].lazy*(len-(len>>));
node[now<<^].sum+=node[now].lazy*(len>>);
node[now<<].maxn+=node[now].lazy;
node[now<<^].maxn+=node[now].lazy;
node[now<<].mins+=node[now].lazy;
node[now<<^].mins+=node[now].lazy;
node[now].lazy=;
}
}
void pushdown_set(int now)
{
if (node[now].lazyset)
{
int len=node[now].r-node[now].l+;
node[now<<].lazyset=node[now].lazyset;
node[now<<^].lazyset=node[now].lazyset;
node[now<<].sum=node[now].lazyset*(len-(len>>));
node[now<<^].sum=node[now].lazyset*(len>>);
node[now<<].maxn=node[now].lazyset;
node[now<<^].maxn=node[now].lazyset;
node[now<<].mins=node[now].lazyset;
node[now<<^].mins=node[now].lazyset;
node[now].lazyset=;
}
}
void update(int L, int R, mint v, int now)///区间更新
{
if(L<=node[now].l&&node[now].r<=R)
{
node[now].lazy+=v;
node[now].sum+=(node[now].r-node[now].l+)*v;
node[now].maxn+=v;
node[now].mins+=v;
return ;
}
pushdown(now);
if(L<=mid)
update(L, R, v, now<<);
if(R>mid)
update(L, R, v, now<<^);
pushup(now);
}
mint query(int L, int R, int now)///区间求和
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].sum;
pushdown(now);
mint ret=;
if(L<=mid)
ret+=query(L, R, now<<);
if(R>mid)
ret+=query(L, R, now<<^);
return ret;
} void addn(int now)///将1~n的节点里的值保存到一个sav[]数组里
{
for(mint i=node[now].l; i<=node[now].r; i++)
sav[i]+=node[now].sum;
if(node[now].l==node[now].r)
return;
addn(now<<);
addn(now<<^);
} mint querymin(int L,int R,int now)///L~R的最小值
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].mins;
pushdown(now);
if(L<=mid)
ret=Min(ret, querymin(L,R,now<<));
if(R>mid)
ret=Min(ret, querymin(L,R,now<<^));
return ret;
} mint querymax(int L,int R,int now)///L~R的最大值
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].maxn;
pushdown(now);
if(L<=mid)
ret=Max(ret, querymax(L,R,now<<));
if(R>mid)
ret=Max(ret, querymax(L,R,now<<^));
return ret;
} void print(int now)///输出所有叶子节点
{
if(node[now].l==node[now].r)
printf("%lld ", node[now].sum);
else
{
print(now<<);
print(now<<^);
}
}
mint getsum(int x, int y)///表示求树从x到y结点最短路径上所有节点的值之和
{
mint ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);///把x点改为所在链顶端的深度更深的那个点
ans+=query(id[top[x]], id[x], );///一条链一条链的求和
x=fa[top[x]];///往高处跑
}
if(dep[x]>dep[y])
swap(x, y);
return ans+query(id[x], id[y], );
}
void updrag(int x, int y, mint k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update(id[top[x]], id[x], k, );
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
update(id[x], id[y], k, );
}
mint qson(int x)///表示求以x为根节点的子树内所有节点值之和
{
ret=;
query(id[x], id[x]+siz[x]-, );///他有siz[x]-1个子节点;
return ret;
}
void updson(int x, int k)///表示将以x为根节点的子树内所有节点值都加上k
{
update(id[x], id[x]+siz[x]-, k, );
}
}tree; void init()
{
Q(head, -);
Q(son, );
sz=;
cnt=;
} void DFS(int now, int DEP, int F)
{
fa[now]=F;
dep[now]=DEP;
siz[now]=;
int key=-;
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==F)
continue;
DFS(E[i].to, DEP+, now);
siz[now]+=siz[E[i].to];
if(siz[E[i].to]>key)
son[now]=E[i].to, key=siz[E[i].to];
}
} void DFS_(mint now, mint tp)
{
id[now]=++cnt;
self[cnt]=sav[now];///这个点是build线段树用的
top[now]=tp;///按序将边加入线段树
if(!son[now])
return ;
DFS_(son[now], tp);///重儿子的top[]从重链顶端继承
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==son[now]||E[i].to==fa[now])
continue;
DFS_(E[i].to, E[i].to);///轻儿子top[]为自身
}
}
int main()
{
mint m, r;
while(~scanf("%d%d%d", &n, &m, &r))
{
init();
for(int i=; i<=n; i++)
read(sav[i]);
while(m--)
{
int a, b;
read(a), read(b);
insert_E(a, b);
insert_E(b, a);
}
DFS(, , );
DFS_(, );
tree.build(, n, );
while(r--)
{
char op[];
int x, y, z;
scanf("%s", op);
read(x);
if(op[]=='I')
read(y), read(z), tree.updrag(x, y, z);
else if(op[]=='D')
read(y), read(z), tree.updrag(x, y, -z);
else
printf("%d\n", tree.getsum(x, x));
}
}
return ;
}
树链剖分+线段树
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=;
int fa[N], siz[N], dep[N], son[N];
int id[N], top[N], self[N], cnt;
int sz, head[N];
int sav[N];
int n;
void read(int &x)
{
int f=;x=;char s=getchar();
while(s<''|s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
x*=f;
} struct Ed
{
int to, next;
}E[N*]; void insert_E(int u, int v)
{
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz++;
} struct SZSZ_tree
{
int sum[N];
void init()
{
Q(sum, );
}
int lowbit(int x)
{
return x&(-x);
}
void update(int i, int v)
{
while(i<=n)
{
sum[i]+=v;
i+=lowbit(i);
}
}
int ALL(int i)
{
int res=;
while(i>)
{
res+=sum[i];
i-=lowbit(i);
}
return res;
}
void updrag(int x, int y, int k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update(id[top[x]], k);
update(id[x]+, -k);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
update(id[x], k);
update(id[y]+, -k);
}
}tree; void init()
{
Q(head, -);
Q(son, );
tree.init();
sz=;
cnt=;
}
void DFS(int now, int DEP, int F)
{
fa[now]=F;
dep[now]=DEP;
siz[now]=;
int key=-;
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==F)
continue;
DFS(E[i].to, DEP+, now);
siz[now]+=siz[E[i].to];
if(siz[E[i].to]>key)
son[now]=E[i].to, key=siz[E[i].to];
}
}
void DFS_(int now, int tp)
{
id[now]=++cnt;
self[cnt]=sav[now];///这个点是build线段树用的
top[now]=tp;///按序将边加入线段树
if(!son[now])
return ;
DFS_(son[now], tp);///重儿子的top[]从重链顶端继承
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==son[now]||E[i].to==fa[now])
continue;
DFS_(E[i].to, E[i].to);///轻儿子top[]为自身
}
}
int main()
{
int m, r;
while(~scanf("%d%d%d", &n, &m, &r))
{
init();
for(int i=; i<=n; i++)
read(sav[i]), tree.sum[i]=;
while(m--)
{
int a, b;
read(a), read(b);
insert_E(a, b);
insert_E(b, a);
}
DFS(, , );
DFS_(, );
while(r--)
{
char op[];
int x, y, z;
scanf("%s", op);
read(x);
if(op[]=='I')
read(y), read(z), tree.updrag(x, y, z);
else if(op[]=='D')
read(y), read(z), tree.updrag(x, y, -z);
else
printf("%d\n", tree.ALL(id[x])+sav[x]);
}
}
return ;
}
树链剖分+树状数组
Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组的更多相关文章
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)
题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)
3589: 动态树 Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 405 Solved: 137[Submit][Status][Discuss] ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】
NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
随机推荐
- 关于command 'gcc' failed with exit status 1 解决方法
Python踩坑之路 Setup script exited with error: command 'gcc' failed with exit status 1 由于没有正确安装Python开发环 ...
- Hibernate 应知应会
Hibernate 的关联关系的配置: 一对一外键约束: 举例子是一个丈夫和妻子:[一个丈夫只能有一位妻子] 表结构: CREATE TABLE `tbl_hus` ( `uuid` ) NOT NU ...
- 以太网帧,IP,TCP,UDP首部结构
1.以太网帧的格式 以太网封装格式 2.IP报头格式 IP是TCP/IP协议簇中最为重要的协议.所有的TCP,UDP, ICMP和IGMP数据都以IP数据报格式传输.IP提供的是不可靠.无连接的协议. ...
- bzoj5123 [Lydsy12月赛]线段树的匹配
题意: 线段树是这样一种数据结构:根节点表示区间 [1, n]:对于任意一个表示区间 [l, r] 的节点,若 l < r, 则取 mid = ⌊l+r/2⌋,该节点的左儿子为 [l, mid] ...
- Race to 1 UVA - 11762 (记忆dp概率)
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...
- 【刷题】BZOJ 3926 [Zjoi2015]诸神眷顾的幻想乡
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- Android性能优化:布局优化 详细解析(含<include>、<ViewStub>、<merge>讲解 )
1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如何影响性能 布局影响Android性能的实质:页面的测量 & 绘制时间 1个页面通过递归 完成测量 & ...
- 如何使用火狐下的两款接口测试工具RESTClient和HttpRequester发送post请求
Chrome下有著名的Postman,那火狐也有它的左膀右臂,那就是RESTClient和HttpRequester.这两款工具都是火狐的插件,主要用来模拟发送HTTP请求,HTTP请求最常用的两种方 ...
- 【bzoj4591】超能粒子炮·改
Portal-->bzoj4591 Solution 首先这个模数是一个质数 然后看一下那个\(k\)和\(n\)的范围..行吧Lucas定理咯 但是如果直接求: \[ \sum\limits_ ...
- LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp
这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...