树链剖分模版
来源:互联网 发布:淘宝网能卖军用品 编辑:程序博客网 时间:2024/05/22 05:36
题目:spoj375
树链剖分训练题目
题意:给定一棵n节点的树,有两种操作,①修改某一条边的权值②查询某一条链u-->v的权值最大的边。
分析:树链剖分入门学习
对树链剖分的初步认识:
①把树上的边分为两类:重边和轻边。
②任意两个节点u和v连接的这条链上,重链和轻边的数目都不超过logn(n为总的边数)
很明显,以某个轻节点为根的子树的规模不会超过父亲节点的规模的一半,否则就不是轻节点了。
1.在链u--->v上,轻边数目不超过logn
瞎证明:
lca=LCA(u,v)。
首先证明u-->lca的链上,轻边数目不超过logn。在极端情况下,链上的边全部为轻边。
由于u--->lca的这条链上以每个点为根节点的子树的大小最多为父亲节点的一半,从lca开始往下走,每次节点的数目都会最少减少一半,所以最多减少logn次就会走到底。
同理证明v--->lca的链上,轻边数目不超过logn。
所以,在链u--->v上,轻边数目不超过2*logn.....
2.在链u--->v上,重链的数目不超过logn
瞎证明:
u--->v这条链可以看成一条链有两种颜色(就是重边和轻边),重边为黑,轻边为白。//白边把黑边分成很多段
初始链全部为黑色,现在如何将链涂色,使得黑边的数目最多,明显就是让白色交错在里面,而白色的边最多logn条,所以黑色的链最多也是logn条。
③任意两个节点u和v连接的这条链上,一条重链上重边在线段树里面的编号是连续的,因此可以在线段树里面O(logn)访问。(从u到top[u]这条重链)
④任意两个节点u和v连接的这条链上,轻边在线段树里面的编号不一定连续。
⑤查询和修改的u-->v这条链的时间复杂度为logn*logn
代码:
#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1 const int INF = 2147483647;const int MAXN = 10010;struct node{ int v,next;}List[MAXN*2];int head[MAXN],cnt;int top[MAXN];//top[v]表示v所在的重链的顶端节点int fa[MAXN]; //父亲节点int deep[MAXN];//深度int sz[MAXN];//sz[v]表示以v为根的子树的节点数int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置int fp[MAXN];//和p数组相反int son[MAXN];//重儿子int pos;void init(){ cnt = 0; memset(head,-1,sizeof(head)); pos = 0; memset(son,-1,sizeof(son));memset(fa,-1,sizeof(fa));}void add(int u,int v){ List[cnt].v=v; List[cnt].next=head[u]; head[u]=cnt++;}int dfs1(int cur,int dp) //第一遍dfs求出fa,deep,sz,son{deep[cur]=dp;sz[cur]=1;son[cur]=-1;for(int i=head[cur];~i;i=List[i].next){int to=List[i].v;if(fa[cur]!=to){fa[to]=cur;sz[cur]+=dfs1(to,dp+1);if(son[cur]==-1 || sz[to]>sz[son[cur]])son[cur]=to; }}return sz[cur];}void dfs2(int cur,int sp) //第二遍dfs求出top和p{top[cur]=sp;p[cur]=pos++;fp[p[cur]]=cur;if(son[cur]==-1)return ;dfs2(son[cur],sp);for(int i=head[cur];~i;i=List[i].next){int to=List[i].v;if(to!=son[cur] && fa[cur]!=to)dfs2(to,to);}}//线段树int tree[MAXN<<4];void update(int pos,int v,int l,int r,int rt){if(l==r){tree[rt]=v;return ;}int m=(l+r)>>1;if(pos<=m)update(pos,v,lson);elseupdate(pos,v,rson);tree[rt]=max(tree[rt<<1],tree[rt<<1|1]); }int query(int L,int R,int l,int r,int rt){if(L<=l && r<=R)return tree[rt];int m=(l+r)>>1,fg1=-INF,fg2=-INF;if(L<=m)fg1=query(L,R,lson);if(R>m)fg2=query(L,R,rson);return max(fg1,fg2);}int Q(int L,int R){return query(L,R,1,pos,1);}int find(int u,int v)//查询u->v边的最大值{ int f1 = top[u], f2 = top[v]; int tmp = 0; while(f1 != f2) { if(deep[f1] < deep[f2]) { swap(f1,f2); swap(u,v); } tmp = max(tmp,Q(p[f1],p[u])); //f1在线段树里面的编号比u小 u = fa[f1]; f1 = top[u]; } if(u == v)return tmp; if(deep[u] > deep[v]) swap(u,v); return max(tmp,Q(p[son[u]],p[v]));}int e[MAXN][3];int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; int n; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); for(int i = 0;i < n-1;i++) { scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); add(e[i][0],e[i][1]); add(e[i][1],e[i][0]); } dfs1(1,1); dfs2(1,1); for(int i = 0;i < n-1; i++) { if(deep[e[i][0]] > deep[e[i][1]]) swap(e[i][0],e[i][1]); update(p[e[i][1]],e[i][2],1,pos,1); } char op[10]; int u,v; while(scanf("%s",op) == 1) { if(op[0] == 'D')break; scanf("%d%d",&u,&v); if(op[0] == 'Q') printf("%d\n",find(u,v)); else update(p[e[u-1][1]],v,1,pos,1); } } return 0;}
- 树链剖分模版
- 树链剖分模版
- 树链剖分模版
- 树链剖分 模版
- 树链剖分模版
- hdu 3966 树链剖分模版
- 树链剖分(模版)
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- 模版
- CodeForcesGym 100733G No Negations
- htm基础学习篇---语法基础
- 野人学Android第二弹——自定义ListView第一课
- UVALive(LA) 3644 X-Plosives (并查集)
- 聪哥跟你说linux命令
- 树链剖分模版
- 第一个OC的类
- 如何识别一个字符串是否Json格式
- Backbone系列:todo的demo
- 门诊医生工作站处方类型的修改-----运维日志3
- 阿里巴巴2014研发工程师实习生面试经历
- C语言中预处理命令#define的用法
- 设计模式C++实现——工厂模式
- java版的无向图结构的存储及DFS操作