BZOJ 1036 && 树链剖分
还是太弱啊。。各种数据结构只听过名字却没有一点概念。。树链剖分也在这个范畴。。今天来进一步深化一下教育改革推进全民素质提高。
性质
忘了在哪里看到的一篇blog有一句话讲得非常好,树链剖分不是一种数据结构,它只是将二维的树hash到一条一维的链上,为运用各种其他数据结构创造条件。
构造方法(或者说标准 并不知道为什么,然而它就是这么剖的,按照每个节点的儿子个数,相对应地接在其父节点后或自己自成一条重链——这样貌似在平均情况下可以使分成的链条数最少,每条链上的点多——不然为什么不按照顺序...更简单..
维护方法
在一条链上不套个什么东西都太浪费了,那么当我们要更新一条路径时,因为在同一条重链上的点的重编号是连续的,我们可以很方便的更新,再联想我们平时暴力更新的做法——lca,那么我们就可以用这种思想将两个点不断调整上移直到两个点在一条重链内,那么更新的操作就完成了。
BZOJ1036:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
终于还是A掉了,发现了两个问题..
一个是读入修改的时候忘记把读入的点的编号改成在链中的编号了,这真的是非常。。还有一个就是在LCA往上走的时候在最后自作聪明的想去掉重复——然而结果就是最后那个点根本就不会算!
不管怎么说又多了一个版子——虽然这么长(然而貌似还可以了,毕竟手打并无参考...时间虽然不是非常优秀(比黄学长快啦啦啦
/**************************************************************
Problem: 1036
User: wyc184
Language: C++
Result: Accepted
Time:2400 ms
Memory:7300 kb
****************************************************************/ #define me AcrossTheSky
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#define lowbit(x) (x)&(-x)
#define INF 1070000000
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define FORP(i,a,b) for(int i=(a);i<=(b);i++)
#define FORM(i,a,b) for(int i=(a);i>=(b);i--)
#define ls(a,b) (((a)+(b)) << 1)
#define rs(a,b) (((a)+(b)) >> 1)
#define MAXN 60001
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
/*==================split line==================*/
struct Edge{
int x,y;
}e[MAXN*2]; int q,xx,L,R;
int n,sume;
int fa[MAXN],size[MAXN],depth[MAXN],sonh[MAXN],ord[MAXN],top[MAXN];
int first[MAXN],next[MAXN];
int max(int a,int b){
return a>b?a:b;
}
struct Interval_Tree{ //线段树最大值和和的维护
int _max[MAXN*2],_sum[MAXN*2],v[MAXN*2]; void updata(int node,int l,int r){
if (l==r) {
v[node]=xx; _max[node]=xx; _sum[node]=xx;
return;
}
int mid=rs(l,r); int lc=ls(node,0),rc=lc+1;
if (q<=mid) updata(lc,l,mid);
else updata(rc,mid+1,r); _max[node]=max(_max[lc],_max[rc]);
_sum[node]=_sum[lc]+_sum[rc];
}
int Max(int node,int l,int r){
if (L<=l && r<=R) return _max[node]; int mid=rs(l,r),lc=ls(node,0),rc=lc+1,m=-INF;
if (L<=mid) m=max(m,Max(lc,l,mid));
if (mid<R) m=max(m,Max(rc,mid+1,r));
return m;
}
int Sum(int node,int l,int r){
if (L<=l && r<=R) return _sum[node]; int mid=rs(l,r),lc=ls(node,0),rc=lc+1,tot=0;
if (L<=mid) tot+=Sum(lc,l,mid);
if (R>mid) tot+=Sum(rc,mid+1,r);
return tot;
}
void check(){
FORP(i,1,n*2) printf("%d ",_max[i]);
cout << endl;
}
}tree;
void addedge(int x,int y){ //邻接表的添加
e[sume].x=x,e[sume].y=y;
next[sume]=first[x];
first[x]=sume;
}
int build_tree(int node,int dep){//树上结点的深度、儿子总数、父亲以及重儿子的维护
depth[node]=dep;
int Max=0,u=0;
for (int i=first[node];i!=-1;i=next[i]){
if (e[i].y!=fa[node]){
fa[e[i].y]=node; int counter=build_tree(e[i].y,dep+1);
if (counter>Max) { Max=counter; u=e[i].y; }
size[node]+=counter;
}
}
sonh[node]=u;
return size[node]+1;
}
int p=1;
void mark(int node,int topn){//重新编号
ord[node]=p;top[node]=topn; if (sonh[node]!=0) {
p++; mark(sonh[node],topn);
}
for (int i=first[node];i!=-1;i=next[i])
if (e[i].y!=fa[node] && e[i].y!=sonh[node]){
p++;
mark(e[i].y,e[i].y);
}
return ;
}
int QSUM(int a,int b){ //求两个点之间的路径和 ——这些操作都是在重编号下完成的
int sum=0;
while (top[a]!=top[b]){ //如果两个点不在一条重链上
if (depth[top[a]]<depth[top[b]]){ //比较两条重链的深度,将深的那条往上调
L=ord[b],R=ord[top[b]]; if (L>R) swap(L,R);
sum+=tree.Sum(1,1,n); //线段树查询
b=fa[top[b]]; //将b更新为这条重链头的父亲
}
else {
L=ord[a],R=ord[top[a]]; if (L>R) swap(L,R);
sum+=tree.Sum(1,1,n);
a=fa[top[a]];
}
}
L=ord[a]; R=ord[b]; if(L>R) swap(L,R);
sum+=tree.Sum(1,1,n);
return sum;
} int QMAX(int a,int b){
int maxx=-INF;
while (top[a]!=top[b]){
if (depth[top[a]]<depth[top[b]]){
L=ord[b],R=ord[top[b]]; if (L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
b=fa[top[b]];
}
else {
L=ord[a],R=ord[top[a]]; if (L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
a=fa[top[a]];
}
}
L=ord[a]; R=ord[b]; if(L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
return maxx;
}
int main(){
cin >> n;
for (int i=1;i<=n;i++) first[i]=-1,size[i]=0; FORP(i,1,n-1){
int x,y; scanf("%d%d",&x,&y);
sume++; addedge(x,y);
sume++; addedge(y,x);
} FORP(i,1,n) fa[i]=i; size[1]=build_tree(1,1)-1; mark(1,1); FORP(i,1,n){
q=ord[i]; scanf("%d",&xx);
tree.updata(1,1,n);
}
int k; cin >> k;
FORP(i,1,k){
char s[10]; scanf("%s",s);
if (s[0]=='C') {
scanf("%d%d",&q,&xx);
q=ord[q];
tree.updata(1,1,n);
continue;
}
int x,y; scanf("%d%d",&x,&y);
if (s[2]=='A') printf("%d\n",QMAX(x,y));
else printf("%d\n",QSUM(x,y));
}
}
BZOJ 1036 && 树链剖分的更多相关文章
- BZOJ 4326 树链剖分+二分+差分+记忆化
去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! #include <iostream> #include <cstring> #i ...
- bzoj 3083 树链剖分
首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区 ...
- bzoj 2243 树链剖分
2013-11-19 16:21 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分,用线段树记录该区间的颜色段数,左右端点颜 ...
- bzoj 4196 树链剖分 模板
[Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2135 Solved: 1232[Submit][Status][D ...
- BZOJ 4811 树链剖分+线段树
思路: 感觉这题也可神了.. (还是我太弱) 首先发现每一位不会互相影响,可以把每一位分开考虑,然后用树链剖分或者LCT维护这个树 修改直接修改,询问的时候算出来每一位填0,1经过这条链的变换之后得到 ...
- HYSBZ 1036树链剖分
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从 ...
- BZOJ 4034 树链剖分
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题意:中文题面 思路:树链剖分入门题. 剖分后就是一个简单的区间更新和区间求和问题. ...
- BZOJ 2286 树链剖分+DFS序+虚树+树形DP
第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. #include <iostream> #include <cstring> #include <cstdio& ...
- BZOJ 3083 树链剖分+倍增+线段树
思路: 先随便选个点 链剖+线段树 1操作 就直接改root变量的值 2操作 线段树上改 3操作 分成三种情况 1.new root = xx 整个子树的min就是ans 2. lca(new roo ...
随机推荐
- JAVA-- M选N的组合算法
M选N的组合算法 只要每个数字出现一次就可以 举例 :也就是说123与321和213属于重复 只算一组 此算法已经排除了重复数据 应用--彩票的注数算法 本程序的思路是开一个数组b,其长度 ...
- [BZOJ1064][Noi2008]假面舞会
[BZOJ1064][Noi2008]假面舞会 试题描述 一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会.今年的面具都是主办方特别定制的.每个参加舞会的人都可以在入场时选择一 个自己喜欢 ...
- java中queue的使用
Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Queue接 口.Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类 ...
- 1-2+3-4+5-6+7......+n的几种实现
本文的内容本身来自一个名校计算机生的一次面试经历,呵呵,没错,你猜对了,肯定 不是我 个人很喜欢这两道题,可能题目原本不止两道,当然,我这里这分析我很喜欢的两道. 1.写一个函数计算当参数为n(n很大 ...
- C++纯虚函数
本文较为深入的分析了C++中虚函数与纯虚函数的用法,对于学习和掌握面向对象程序设计来说是至关重要的.具体内容如下: 首先,面向对象程序设计(object-oriented programming)的核 ...
- 【转】利用mybatis-generator自动生成代码
本文转自:http://www.cnblogs.com/yjmyzz/p/4210554.html mybatis-generator有三种用法:命令行.eclipse插件.maven插件.个人觉得m ...
- iOS 关于多线程的一些知识点(不断更新)
1.NSOperation 对于NSOperation,In OS X v10.6 and later, operation queues ignore the value returned by t ...
- Java for LeetCode 044 Wildcard Matching
Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character. ...
- css3学习总结9--CSS3过渡
CSS3 过渡 通过 CSS3,我们可以在不使用 Flash 动画或 JavaScript 的情况下,当元素从一种样式变换为另一种样式时为元素添加效果. 过渡属性 属性 描述 CSS transiti ...
- ipconfig 无效
刚刚配置了很多的环境变量后,在命令行下输入ipconfig后无效了 于是在环境变量PATH底下再次加入了;C:\WINDOWS\system32; 从新运行ipconfig,问题解决