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< ...
随机推荐
- Aspose.cell生成表格
public void ExportQueryPrj(HttpContext context) { //接受前端传递参数和数据 st ...
- mysql存储方式MyISAM 和 InnoDB的区别
MyISAM 和 InnoDB 讲解: InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级 ...
- log4net 最快速体验
本文供实习司机快速上手log4net最基本功能,共4步,3分钟搞定. 一.添加log4net.dll引用,可使用nuget安装或直接引用文件 二.添加配置 在app.config或web.config ...
- Laravel项目的结构文章
http://esbenp.github.io/2016/04/11/modern-rest-api-laravel-part-1/
- 面向对象之套接字(socket)和黏包
一丶套接字(socket) tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 基于UDP协议的socket server端: import socket udp_sk = socke ...
- 如何在Ubuntu server中修改IP
详细请移步至博客https://blog.csdn.net/shenzhen_zsw/article/details/74025066 方法一. sudo ifconfig eth0 100.100 ...
- GBase数据库存储过程——批量查询多个数据表的磁盘占用情况
--清理历史表,可选 DROP TABLE IF EXISTS `dap_model`.`data_statics`; CREATE TABLE `dba`.`data_statics` ( `TAB ...
- D3 学习
D3 学习笔记 D3简介 D3全称是Data-Driven Documents数据驱动文档,是一个开源的javascript库,可以用于数据可视化图形的创建,但不仅仅只是这些.可以查看d3帮助文档还有 ...
- #linux 下Sublime的安装
1.Download http://www.sublimetext.com/2 Installtion use tar 解压压缩包,这里我将包改了个名字,这样就不用写空格的转义字符了,改成Subli ...
- hdu-1875 畅通工程再续---MST
题目链接: https://vjudge.net/problem/HDU-1875 题目大意: 相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小 ...