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< ...
随机推荐
- @Enable*注解的工作原理
@EnableAspectJAutoProxy @EnableAsync @EnableScheduling @EnableWebMv @EnableConfigurationProperties @ ...
- WebAPI项目添加定时服务
开发平台: VS2019 背景: 在开发小程序的API服务的时候,由于access_token的有效期为7200秒,也就是2小时,这就需要后端定时的去更新这个access_token,便于调用小程序的 ...
- vue-初识
一:vue基础1.1.Vue是一套构建用户界面的渐进式框架1.2.引入vue:<script src="https://unpkg.com/vue/dist/vue.js"& ...
- mybatis-关联关系2
关系关系主要有一对一,一对多,多对多,往往多对多都是通过俩个一对多来完成的 实例项目还是之前的,只是增加了一个年级实体类 1.创建年级实体类:---年级中有学生的集合 package com.java ...
- BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树
4541: [Hnoi2016]矿区 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 433 Solved: 182[Submit][Status][ ...
- Sonar服务器搭建
Sonar服务器搭建 Sonar概述 Sonar 是一个用于代码质量管理的开放平台.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具.与持续集成工具(例如 Hudson ...
- 【BZOJ1101】[POI2007] Zap(莫比乌斯反演)
点此看题面 大致题意: 求\(\sum_{x=1}^N\sum_{y=1}^M[gcd(x,y)==d]\). 一道类似的题目 推荐先去做一下这道题:[洛谷2257]YY的GCD,来初步了解一下莫比乌 ...
- Problem K: 搜索基础之棋盘问题
Problem K: 搜索基础之棋盘问题 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 92 Solved: 53[Submit][Status][W ...
- cloudera manager的卸载以及重新安装
1 卸载cloudera 参照 http://www.cnblogs.com/chenfool/p/3738540.html Cloudera 的官方介绍: http://www.cloudera.c ...
- 题解 CF734A 【Anton and Danik】
本蒟蒻闲来无事刷刷水题 话说这道题,看楼下的大佬们基本都是用字符 ( char ) 来做的,那么我来介绍一下C++的优势: string ! string,也就是类型串,是C语言没有的,使用十分方便 ...