题目链接:https://vjudge.net/contest/279350#problem/A

题目大意:n个点,m条边,然后q次询问,因为在树上,两个点能确定一条直线,我们可以对这条直线上的所有值进行加减操作,也可以单点询问。

各个数组的作用:sto是刚开始的输入数据,head是前向星,dfsnum指的是dfs序,depth指的是每个点的深度son指的是每个节点的重儿子,father指的是每个点的父节点,Size指的是以当前点为根节点的树,ord指的是遍历顺序,cost指的是编号之后的每个点,top指的是当前的这条重链的最顶端的那个点,剩下的就是线段树的数组了。

注意点:我们通过两个dfs来给这些数组赋值,通过第一个dfs,我们可以把depth和father,size,son求出来,剩下的ord和top通过第二个dfs求出来,为什么使用两个dfs?我的理解就是,第一个dfs和第二个dfs的遍历条件并不相同,第一个dfs就是能走就走,第二个dfs是在按照已经分好链的前提下进行走的,也就是说这里的ord数组并不能在第一个dfs中实现,只能在第二个数组中实现。(后续有新的理解会继续补充)。

AC代码:

 #include<iostream>
#include<cmath>
#include<stack>
#include<queue>
#include<stdio.h>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
# define inf 0x3f3f3f3f
# define ll long long
# define lson l,m,rt<<
# define rson m+,r,rt<<|
const int maxn = 5e4+;
int sto[maxn],head[maxn],edgnum,dfsnum,depth[maxn];
int son[maxn],father[maxn],Size[maxn],ord[maxn],cost[maxn],top[maxn];
int tree[maxn<<],lazy[maxn<<];
struct node
{
int to;
int nex;
} edge[maxn<<];
void addedge(int fr,int to)
{
edge[edgnum].nex=head[fr];
edge[edgnum].to=to;
head[fr]=edgnum++;
}
void dfs1(int fr,int rt,int dep)
{
father[fr]=rt;
Size[fr]=;
son[fr]=-;
depth[fr]=dep;
for(int i=head[fr]; i!=-; i=edge[i].nex)
{
int to=edge[i].to;
if(to==rt)
continue;
dfs1(to,fr,dep+);
Size[fr]+=Size[to];
if(son[to]==-||(Size[son[fr]]<Size[to]))
{
son[fr]=to;
}
}
}
void dfs2(int fr,int rt)
{
ord[fr]=++dfsnum;
cost[ord[fr]]=sto[fr];
top[fr]=rt;
if(son[fr]!=-)
dfs2(son[fr],rt);
for(int i=head[fr]; i!=-; i=edge[i].nex)
{
int u=edge[i].to;
if(son[fr]!=u&&father[fr]!=u)
{
dfs2(u,u);
}
}
}
void init()
{
dfsnum=;
dfs1(,-,);
dfs2(,);
}
void up(int rt)
{
tree[rt]=tree[rt<<]+tree[rt<<|];
}
void down(int len,int rt)
{
if(lazy[rt])
{
lazy[rt<<]+=lazy[rt];
lazy[rt<<|]+=lazy[rt];
tree[rt<<]+=(len-len/)*lazy[rt];
tree[rt<<|]+=(len/)*lazy[rt];
lazy[rt]=;
}
}
void buildtree(int l,int r,int rt)
{
lazy[rt]=;
tree[rt]=;
if(l==r)
{
tree[rt]=cost[l];
return ;
}
int m=(l+r)>>;
buildtree(lson);
buildtree(rson);
up(rt);
}
void update(int l,int r,int rt,int L,int R,int p)
{
if(L<=l&&R>=r)
{
tree[rt]+=p*(r-l+);
lazy[rt]+=p;
return ;
}
down(r-l+,rt);
int m=(l+r)>>;
if(L<=m)
update(lson,L,R,p);
if(R>m)
update(rson,L,R,p);
up(rt);
}
void Update(int n,int x,int y,int p)
{
int tx=top[x],ty=top[y];
while(tx!=ty)
{
if(depth[tx]<depth[ty])
{
swap(tx,ty);
swap(x,y);
}
update(,n,,ord[tx],ord[x],p);
x=father[tx],tx=top[x];
}
if(depth[x]<depth[y])
{
swap(x,y);
}
update(,n,,ord[y],ord[x],p);
}
int query(int l,int r,int rt,int pos)
{
if(l==r)
{
return tree[rt];
}
down(r-l+,rt);
int ans=;
int m=(l+r)>>;
if(pos<=m)
ans+=query(lson,pos);
if(pos>m)
ans+=query(rson,pos);
return ans;
up(rt);
}
int main()
{
int n,m,q;
while(~scanf("%d %d %d",&n,&m,&q))
{
edgnum=;
for(int i=; i<=n; i++)
{
scanf("%d",&sto[i]);
head[i]=-;
}
int t1,t2;
for(int i=; i<=m; i++)
{
scanf("%d %d",&t1,&t2);
addedge(t1,t2);
addedge(t2,t1);
}
init();
char str[];
buildtree(,n,);
int t3;
while(q--)
{
scanf("%s",str);
if(str[]=='I')
{
scanf("%d %d %d",&t1,&t2,&t3);
Update(n,t1,t2,t3);
}
else if(str[]=='Q')
{
scanf("%d",&t1);
int ans=query(,n,,ord[t1]);
printf("%d\n",ans);
}
else if(str[]=='D')
{
scanf("%d %d %d",&t1,&t2,&t3);
Update(n,t1,t2,-t3);
}
}
}
return ;
}

数链剖分(Aragorn's Story )的更多相关文章

  1. G - Game HDU - 5242 (数链剖分)

    题目链接: G - Game HDU - 5242 题目大意:首先是T组测试样例,给出一颗以1节点为根的树,每个节点有各自的价值,有m次从根节点出发向下走到叶子节点的机会,每次会得到所有经过节点的权值 ...

  2. 线段树&数链剖分

    傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...

  3. 数链剖分(Tree)

    题目链接:https://cn.vjudge.net/contest/279350#problem/D 题目大意:操作,单点查询,区间取反,询问区间最大值. AC代码: #include<ios ...

  4. 数链剖分(树的统计Count )

    题目链接:https://cn.vjudge.net/contest/279350#problem/C 具体思路:单点更新,区间查询,查询的时候有两种操作,查询区间最大值和区间和. 注意点:在查询的时 ...

  5. 数链剖分(Housewife Wind )

     题目链接:https://vjudge.net/contest/279350#problem/B 题目大意:给你n,q,s.n指的是有n个点,q代表有q次询问,s代表的是起点.然后接下来会有n-1条 ...

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

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

  7. 浅谈树链剖分(C++、算法、树结构)

    关于数链剖分我在网上看到的有几个比较好的讲解,本篇主要是对AC代码的注释(感谢各位witer的提供) 这是讲解 http://www.cnblogs.com/kuangbin/archive/2013 ...

  8. POJ 3237 Tree (树链剖分)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 2825   Accepted: 769 Description ...

  9. 1036: [ZJOI2008]树的统计Count (树链剖分)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3401  Solved: 1418[Submit] ...

随机推荐

  1. 《Linux内核分析》第五周:分析system_call中断处理过程

    实验 分析system_call中断处理过程 使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shiyanlou.com/xref/l ...

  2. 专业实训题目需求分析(3D推箱子)

    业务需求:    游戏提供主菜单让玩家进行游戏设置.帮助说明,推箱子的小人可以前后左右转动,箱子可以被上下左右的推动,要有关卡设置,障碍物设置,游戏提供背景音乐的功能,要实现3D效果. 面向的用户类型 ...

  3. “吃神么,买神么”的第一个Sprint计划(结束)

    “吃神么,买神么”项目Sprint计划 ——5.28  星期四(第八天)第一次Spring计划结束   第一阶段Spring的目标以及完成情况: 时间:5月21号~5月28号(7天) 目标:第一阶段结 ...

  4. RabbitMQ None of the specified endpoints were reachable

    消息队列部署到服务器的时候,需要新增一个用户,然后一定要设置权限.参考一下 https://www.cnblogs.com/gossip/p/4573056.html

  5. ESLint的使用

    ESLint是在ECMAScript/JavaScript代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误.在许多方面,它和JSLint.JSHint相似,除了少数的例外: ESL ...

  6. 【BZOJ1488】[HNOI2009]图的同构(Burside引理,Polya定理)

    [BZOJ1488][HNOI2009]图的同构(Burside引理,Polya定理) 题面 BZOJ 洛谷 题解 求本质不同的方案数,很明显就是群论这套理论了. 置换一共有\(n!\)个,考虑如何对 ...

  7. 【贪心策略】渡河(river)

    “假舟楫者,非能水也,而绝江河.”这句话说的是,借助渡船的人,不是会游水,却能横渡江河. 会游水的人反而不一定能顺利地横渡江河.由于江面风浪很大,他们必须潜泳渡河.这就必须用到氧气瓶.氧气瓶当然是出题 ...

  8. bzoj1345 序列问题 (贪心)

    考虑某个点产生的贡献: 如果i左边是一个比它小的数x,那有两种情况: 1.x的左边的数y大于i,肯定要把x合并到i,i的贡献++ 2.x的左边的数y小于i,那肯定要把x合并到y,而这时候递归地来考虑, ...

  9. hdu5583

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> ...

  10. Java Try-with-resources

    目录 资源管理与 Try-Catch-Finally,旧风格 Try-with-resources 管理多个资源 自定义 AutoClosable 实现 Try-with-resources 是 ja ...