hdu3966 Aragorn's Story 树链剖分
题目大意:
有n个兵营形成一棵树,给出q次操作,每一次操作可以使两个兵营之间的所有兵营的人数增加或者减少同一个数目,每次查询输出某一个兵营的人数。
思路:
树链剖分模板题,讲一下树链剖分过程的理解。
第一步,dfs,记录每个节点的父节点,子节点数目,重子节点,树的深度。
第二步,dfs,处理出dfs序和轻重链的起点,重链形成一条,轻链的起点就是本身,处理dfs序的时候先处理重链的dfs序。
修改,利用树状数组(或者线段树),个人认为这是最难的地方。
inline void change(int u,int v,int d)
{
int f1=top[u],f2=top[v];
while(f1!=f2)
{
if(deep[f1]<deep[f2])
{
swap(f1,f2),swap(u,v);
}
upp(p[f1],d);
upp(p[u]+1,-d);//每次更新一条链
u=fa[f1]; //处理完后必须往父节点走,否则死循环
f1=top[u];
}
if(deep[u]>deep[v])swap(u,v);//最后处在同一条重链上时,重链的上半部分是不需要更新的
upp(p[u],d);
upp(p[v]+1,-d); }
查询,树状数组,由于每次修改的时候都是通过change来实现的而不是up来实现的,所以树状数组getsum得到的就是某一个点的值而不是前缀和。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cstring>
#include<queue>
#include<stack>
#include<stdlib.h>
#include<unordered_map>
#define CLR(a,b) memset(a,b,sizeof(a))
#define mkp(a,b) make_pair(a,b)
typedef long long ll;
using namespace std;
const int maxn=;
int n,m,q,tot,head[maxn],rs[maxn],A[maxn],pos=;
struct edge{
int to,Next;
}a[maxn*];
inline void init(){
tot=;
CLR(rs,);
CLR(head,-);
pos=;
}
inline void addv(int u,int v){
a[++tot]={v,head[u]};
head[u]=tot;
}
inline int lowbit(int x){return x&(-x);}
inline void upp(int x,int val)
{
while(x<=n)
{
rs[x]+=val;
x+=lowbit(x);
}
}
inline getsum(int x)
{
int ans=;
while(x)
{
ans+=rs[x];
x-=lowbit(x);
}
return ans;
}
int size[maxn],deep[maxn];
int fa[maxn],son[maxn],top[maxn];
int p[maxn],fp[maxn];
inline void dfs_1(int u,int f,int d)
{
fa[u]=f;
deep[u]=d;
size[u]=;
son[u]=-;
for(int i = head[u] ; i != -;i = a[i].Next)
{
int v=a[i].to;
if(v != f)
{
dfs_1(v,u,d+);
size[u]+=size[v];
if(son[u]==-||size[son[u]]<size[v])
{
son[u]=v;
}
}
}
}
inline void dfs_2(int u,int st)
{
top[u]=st;
p[u]=pos++;
fp[pos]=u;
if(son[u] == -) return;
dfs_2(son[u],st);
for(int i=head[u];i!=-;i=a[i].Next)
{
int v=a[i].to;
if(fa[u]!=v&&son[u]!=v)
dfs_2(v,v);
}
}
inline void change(int u,int v,int d)
{
int f1=top[u],f2=top[v];
while(f1!=f2)
{
if(deep[f1]<deep[f2])
{
swap(f1,f2),swap(u,v);
}
upp(p[f1],d);
upp(p[u]+,-d);//每次更新一条链
u=fa[f1];//往父节点走
f1=top[u];
}
if(deep[u]>deep[v])swap(u,v);
upp(p[u],d);
upp(p[v]+,-d); }
int main(){
while(scanf("%d%d%d",&n,&m,&q)!=EOF)
{
init();
for(int i=;i<=n;i++)
{
scanf("%d",&A[i]);
}
for(int i=;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addv(u,v);
addv(v,u);
}
dfs_1(,-,);
dfs_2(,);
for(int i=;i<=n;i++)
{
change(i,i,A[i]);
}
for(int i=;i<q;i++)
{
char c;
int u,v;
scanf(" %c",&c);
if( c == 'Q' )
{
scanf("%d",&u);
printf("%d\n",getsum(p[u]));
}else{
int d;
scanf("%d%d%d",&u,&v,&d);
if( c == 'D' ) d*=-;
change(u,v,d);
}
}
}
}
hdu3966 Aragorn's Story 树链剖分的更多相关文章
- HDU3669 Aragorn's Story 树链剖分 点权
HDU3669 Aragorn's Story 树链剖分 点权 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: n个点的,m条边,每个点都 ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
- HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)
题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...
- HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问
Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...
- hdu 3966 Aragorn's Story 树链剖分 按点
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 3966 Aragorn's Story (树链剖分入门题)
树上路径区间更新,单点查询. 线段树和树状数组都可以用于本题的维护. 线段树: #include<cstdio> #include<iostream> #include< ...
- HDU 3966 Aragorn's Story 树链剖分
Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. #pragm ...
随机推荐
- apt-get update 时的问题 W:Failed to fetch gzip:/var/lib/apt/lists/partial...解决办法
http://askubuntu.com/questions/149454/upgrade-from-11-04-to-11-10-getting-wfailed-to-fetch-gzip 这个问题 ...
- 微信WeixinJSBridge API 屏蔽右上角分享等常用方法
WeixinJSBridge这个API有几个功能还是相当有用的,比如: 1.隐藏微信网页右上角的按钮(...按钮):开发者可以用这个功能来禁止当前页面被分享 2.隐藏微信网页底部的导航栏(比如前进后退 ...
- 9.hive聚合函数,高级聚合,采样数据
本文主要使用实例对Hive内建的一些聚合函数.分析函数以及采样函数进行比较详细的讲解. 一.基本聚合函数 数据聚合是按照特定条件将数据整合并表达出来,以总结出更多的组信息.Hive包含内建的一些基本聚 ...
- 框架和cms区别
cms:精装房,拎包即可入住 框架:毛坯房,内部装修可根据自己需求来 选择策略:个性化需求不高的话,可以选择cms
- Cookie存中文乱码的问题
有个奇怪的问题:登录页面中使用Cookie存值,Cookie中要存中文汉字.代码在本地调试,一切OK,汉字也能顺利存到Cookie和从Cookie中读出,但是放到服务器上不管用了,好好的汉字成了乱码, ...
- hdu 1905 Pseudoprime numbers
#include<stdio.h> #include<math.h> #define ll long long ll mod; bool Judge(int x) { ;i&l ...
- Session.Abandon-Session.Clear-Session.RemoveAll
System.Web.UI.Page.Session属性和System.Web.HttpContext.Session属性 都是System.Web.SessionState.HttpSessionS ...
- Linux相关常用工具
Xshell Xshell可以在Windows界面下用来访问远端不同系统下的服务器,从而比较好的达到远程控制终端的目的. 通常需要通过vpn访问.建立vpn隧道可以通过FortiClient 或者 I ...
- 编写高质量代码改善C#程序的157个建议——建议3: 区别对待强制转型与as和is
建议3: 区别对待强制转型与as和is 在阐述本建议之前,首先需要明确什么是强制转型,以及强制转型意味着什么.从语法结构上来看,类似下面的代码就是强制转型. secondType = (SecondT ...
- 【Head First Java 读书笔记】(六)认识Java API
第五章 使用Java函数库 ArrayList add(Object elem) remove(int index) remove(Object elem) contains(Object elem) ...