HDU 3966 Aragorn's Story 树链拋分
一、写在前面
终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作。经历了若干长时间之后终于打了出来(为什么每次学什么东西都会强行写3遍左右。。。)
二、题意
阿拉贡同学发现一棵树装的若干营地有了若干敌人(可以是负数),这些敌人的变化情况会使用类似于“A-B之间的路上的所有营地都增加某个数量的人数”来进行。最后任意时间有询问:某个点当前有多少人?
三、题解
树链拋分的思路是这样的:首先把一棵树,对于每个节点都将会有:将子节点数量最多的一条链称为重链,其他各子节点各自组成以他们开头的重链。最终会使得一颗树的形状确定之后,就会唯一确定一个树链拋分方案(可能会在相同子节点的处理上有些分歧)。之后对于路径的寻找,会发现实际上,可以方便的找到任意一条路径,时间复杂度低于logN
对于任意树链拋分代码需要以下几个数组:
child代表某个节点为根节点的子节点的个数
deep代表当前节点的深度
number代表适用树链拋分的方式进行重新编号之后的映射
fa代表父节点编号
top当前重链的开头元素编号
#include<bits/stdc++.h>
using namespace std; #define veci vector<int>
#define ll long long
const long long MAXN=5e4+; int arr[MAXN],child[MAXN],top[MAXN],deep[MAXN],tree[MAXN],fa[MAXN];
veci G[MAXN];
int number[MAXN];
int n,m,p,size=; void insert(int pos,int key)
{
while(pos<MAXN)
{
tree[pos]+=key;
pos+=pos&(-pos);
}
// cout<<pos<<endl;
} ll getSum(int pos)
{
ll ans=;
while(pos)
{
ans+=tree[pos];
pos-=pos&(-pos);
}
// cout<<"checkSum: "<<ans<<ends<<pos<<endl;
return ans;
} void dfs_1(int now,int last,int dep)
{
int len=G[now].size();
fa[now]=last;
deep[now]=dep;
child[now]=;
for(int i=;i<len;++i)
{
int tar=G[now][i];
if(tar==last)continue;
dfs_1(tar,now,dep+);
child[now]+=child[tar];
}
} void dfs(int now,int last,int first)
{
top[now]= first? first:now;
// if(top[now]==now)
// {
// cout<<now<<" checked "<<endl;
// }
int len=G[now].size();
// cout<<now<<"checkNum: "<<size<<endl;
number[now]=size++; int maxx=-;int pos=-;
for(int i=;i<len;++i)
{
int tar=G[now][i];
if(tar==last)continue;
if(maxx<child[tar])
{
maxx=child[tar];
pos=i;
}
}
if(pos!=-)dfs(G[now][pos],now,top[now]);
for(int i=;i<len;++i)
{
int tar=G[now][i];
if(i==pos||tar==last)continue;
dfs(tar,now,);
}
}
void update(int a,int b,int key)
{
// cout<<"checkUP"<<a<<ends<<b<<ends<<key<<endl;
int t1=top[a];
int t2=top[b];
//
while(t1!=t2)
{ if(deep[t1]<deep[t2])
{
swap(t1,t2);
swap(a,b);
}
insert(number[t1],key);
insert(number[a]+,-key);
// cout<<"checkTop: "<<t1<<ends<<a<<endl;
a=fa[t1];
// b=fa[t2];
t1=top[a];
// t2=top[b];
}
int star=min(number[a],number[b]);
int endd=max(number[a],number[b])+;
// cout<<"check_line: "<<star<<ends<<endd<<endl;
insert(star,key);
insert(endd,-key);
} int query(int a)
{
int pos=number[a];
return getSum(pos)+arr[a];
} void init()
{
size=;
for(int i=;i<=n;++i)
{
G[i].clear();
scanf("%d",&arr[i]);
}
memset(tree,,*(n+));
for(int i=;i<n;++i)
{
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}dfs_1(,,);
dfs(,,);
for(int i=;i<p;++i)
{
char c[];
scanf("%s",c);
if(c[]=='I')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(a,b,c); }else if(c[]=='D')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(a,b,-c);
}else if(c[]=='Q')
{
int a;
scanf("%d",&a);
cout<<query(a)<<"\n";
}
}
} int main()
{
// cin.sync_with_stdio(false);
while(scanf("%d%d%d",&n,&m,&p)!=EOF)init(); return ;
}
HDU 3966 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 树链剖分的模版,成段更新单点查询.熟悉线段树的成段更新的话就小case啦. //树链剖分 边权修 ...
- 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 树链剖分+BIT区间修改/单点询问
Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...
- HDU 3966 Aragorn's Story 树链剖分
Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. #pragm ...
- hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询
/** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...
- 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< ...
随机推荐
- 在Magento System Configuration页面添加配置项
以 Jp_Coupon 模块为例: 目标: 在 System configuration 页面添加一个 JP tab, 在JP中添加 Coupon section, 然后给 Coupon sectio ...
- axios拦截器+mockjs
//main.js中 //引入你mock.js文件 require('./mock.js') //封装api请求 //src/axios/api.js import axios from 'axios ...
- vue中background-image图片路径问题
按照以往在css文件中写background:url('图片路径'),完成后加载竟然显示出错,起初以为路径不对,检查了几遍,仍然没有问题.最后百度找答案,发现不少同行都遇到过这种问题,遂记录下自己所采 ...
- linux下mysql多实例安装(转)
转自:http://www.cnblogs.com/xuchenliang/p/6843990.html 1.MySQL多实例介绍 1.1.什么是MySQL多实例 MySQL多实例就是在一台机器上 ...
- cms-首页搭建
主页面主要有3个部分构成,头部.主体内容部分.尾部 1.头部: <%@ page language="java" contentType="text/html; c ...
- Python参数基础
Python参数基础 位置参数 通过位置进行匹配,把参数值传递给函数头部的参数名称,顺序从左到右 关键字参数 调用的时候使用参数的变量名,采用name=value的形式 默认参数 为没有传 ...
- Euerka环境搭建
机器环境 windows10,IntelliJ IDEA 配置host 单节点Eureka 一.pom文件 <?xml version="1.0" encoding=&quo ...
- IOS UITextFieldDelegate (常用的代理方法)
#pragma mark - UITextFieldDelegate // 返回NO代表着文本输入框不可以改变(不可以编辑) - (BOOL)textField:(UITextField *)text ...
- django建议入门-FYI
django 简易博客 现在正式开始博客开发 1安装官方发布版 官方发布的版本带有一个版本号,例如1.0.3或1.1,而最新版本总是可以在http://www.djangoproject.com/do ...
- Java 集合框架_上
集合框架被设计成要满足以下几个目标. 该框架必须是高性能的.基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的. 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性. 对一个集合的 ...