一、写在前面

  终于开始开坑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 树链拋分的更多相关文章

  1. HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树

    HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...

  2. Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)

    题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...

  3. HDU 3966 Aragorn's Story (树链点权剖分,成段修改单点查询)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 树链剖分的模版,成段更新单点查询.熟悉线段树的成段更新的话就小case啦. //树链剖分 边权修 ...

  4. HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)

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

  5. HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问

    Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...

  6. HDU 3966 Aragorn's Story 树链剖分

    Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. #pragm ...

  7. hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询

    /** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...

  8. hdu 3966 Aragorn's Story 树链剖分 按点

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

  9. HDU 3966 Aragorn's Story (树链剖分入门题)

    树上路径区间更新,单点查询. 线段树和树状数组都可以用于本题的维护. 线段树: #include<cstdio> #include<iostream> #include< ...

随机推荐

  1. linux笔记学习大全,包括相关软件

    1.如果tomcat正常启动,内部浏览器可以访问,外部电脑的浏览器布恩那个访问? 可以使用如下命令: iptables -F firewall-cmd --add-port=8080/tcp --pe ...

  2. 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "XXXView" nib but the view outlet was not set.' 崩溃问题

    先说下我遇到这个崩溃问题的原因: 自定义的Viewxib和系统的 View重名,导致崩溃 我的理解是我这里加载YJLoginViewController 的时候,YJLoginViewControll ...

  3. Callable的简单使用

    说起java的线程操作,都会想到Thread和Runable这两个, 这两个类可以实现异步和同步. 在大多数的java开发中, 这两个都是实现异步的线程来使用, 但是现在考虑一种情况: 发出一条线程, ...

  4. Spring MVC的测试

    测试是保证软件质量的关键. 与 Spring MVC 相关的测试,主要涉及控制器的测试. 为了测试Web项目通常不需要启动项目,需要一些Servlet相关的一些模拟对象,比如MockMVC.MockH ...

  5. 华为服务器操作系统EulerOS V2.0

    平台: linux 类型: 虚拟机镜像 软件包: java-1.8.0 php-5.4.16 python-2.7.5 qt-4.8.5 tomcat-7.0.69 basic software eu ...

  6. Excel2Dataset

    //获取用户打开的Excel文档路径 private stringkkk() { OpenFileDialog selectFile = new OpenFileDialog(); selectFil ...

  7. HDU1430 BFS + 打表 + 康托展开

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题. 这道题要用到很多知识,康托展开.BFS.打表的预处理还要用到一一映射,做完 ...

  8. pta 编程题10 Root of AVL Tree

    其它pta数据结构编程题请参见:pta 这道题考察平衡二叉查找树的插入. 为了保证二叉查找树的平衡,当一个结点的左右子树的高度差大于1时就要进行调整. 分为以下四种情况: 插入新节点后,以及旋转之后, ...

  9. 撸了个 django 数据迁移工具 django-supertube

    撸了个 django 数据迁移工具 django-supertube 支持字段映射和动态字段转化. 欢迎 star,issue https://github.com/FingerLiu/django- ...

  10. fiddle连接终端测试配置

    第一次做app,对app的数据要进行一些数据抓包和数据分析,知道客户端发送到服务器端的过程和逻辑,通过抓包了解和分析出错,前提要先连接fiddle