关于轻重边及树链剖分该怎么写...
AC BZOJ 1787 轻重边剖分LCA
1 #include <cstdio> 2 #include <fstream> 3 #include <iostream> 4 5 #include <cstdlib> 6 #include <cstring> 7 #include <algorithm> 8 #include <cmath> 9 10 #include <queue> 11 #include <vector> 12 #include <map> 13 #include <set> 14 #include <stack> 15 #include <list> 16 17 typedef unsigned int uint; 18 typedef long long int ll; 19 typedef unsigned long long int ull; 20 typedef double db; 21 22 using namespace std; 23 24 inline int getint() 25 { 26 int res=0; 27 char c=getchar(); 28 bool mi=false; 29 while(c<'0' || c>'9') mi=(c=='-'),c=getchar(); 30 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); 31 return mi ? -res : res; 32 } 33 inline ll getll() 34 { 35 ll res=0; 36 char c=getchar(); 37 bool mi=false; 38 while(c<'0' || c>'9') mi=(c=='-'),c=getchar(); 39 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); 40 return mi ? -res : res; 41 } 42 43 //============================================================================== 44 //============================================================================== 45 //============================================================================== 46 //============================================================================== 47 48 const int INF=(1<<28)-1; 49 50 51 struct edge 52 { int in; edge*nxt; }; 53 edge*eds[505000]; 54 int ecnt=10000; 55 edge*et; 56 void addedge(int a,int b) 57 { 58 if(ecnt==10000) { ecnt=0; et=new edge[10000]; } 59 et->in=b; et->nxt=eds[a]; eds[a]=et++; 60 ecnt++; 61 } 62 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt) 63 64 //nodes 65 int f[505000]; //father node 66 int ch[505000]; //chain 67 int dep[505000]; //depth of node 68 69 //chains 70 int ctot=0; 71 int h[505000]; //head of chain 72 73 int n,m,k; 74 75 int BuildTree(int x) 76 { 77 int sum=0; 78 int mx=0; 79 int mxp=-1; 80 81 FOREACH_EDGE(e,x) 82 if(e->in!=f[x]) 83 { 84 dep[e->in]=dep[x]+1; 85 f[e->in]=x; 86 int v=BuildTree(e->in); 87 sum+=v; 88 if(v>mx) 89 { 90 mx=v; 91 mxp=e->in; 92 } 93 } 94 95 if(mxp==-1) //leaf 96 { 97 ch[x]=ctot; 98 h[ctot]=x; 99 ctot++; 100 } 101 else 102 { 103 ch[x]=ch[mxp]; 104 h[ch[x]]=x; 105 } 106 107 return sum+1; 108 } 109 110 111 int getlca(int a,int b) 112 { 113 while(ch[a]!=ch[b]) 114 { 115 if(dep[h[ch[a]]]<dep[h[ch[b]]]) swap(a,b); 116 a=f[h[ch[a]]]; 117 } 118 return dep[a]>dep[b] ? b : a; 119 } 120 121 int dist(int a,int b) 122 { 123 int lca=getlca(a,b); 124 return dep[a]+dep[b]-dep[lca]-dep[lca]; 125 } 126 127 int main() 128 { 129 n=getint(); 130 m=n-1; 131 k=getint(); 132 for(int i=0;i<m;i++) 133 { 134 int a=getint()-1; 135 int b=getint()-1; 136 addedge(a,b); 137 addedge(b,a); 138 } 139 140 BuildTree(0); 141 142 for(int i=0;i<k;i++) 143 { 144 int a=getint()-1; 145 int b=getint()-1; 146 int c=getint()-1; 147 int l1=getlca(a,b); 148 int l2=getlca(b,c); 149 int l3=getlca(a,c); 150 151 int resp,resd; 152 153 if(l1==l2) 154 { 155 resp=l3; 156 resd=dist(a,l3)+dist(b,l3)+dist(c,l3); 157 } 158 else if(l2==l3) 159 { 160 resp=l1; 161 resd=dist(a,l1)+dist(b,l1)+dist(c,l1); 162 } 163 else if(l1==l3) 164 { 165 resp=l2; 166 resd=dist(a,l2)+dist(b,l2)+dist(c,l2); 167 } 168 169 printf("%d %d\n",resp+1,resd); 170 } 171 172 return 0; 173 }
View Code
题解好神......两两求LCA,选择那个非公共LCA.....怎么做到的.....
看起来HLD打熟练了应该是很好写的.....
代码的运行时间拿了个rank8...
AC BZOJ 3631 树链剖分
1 #include <cstdio> 2 #include <fstream> 3 #include <iostream> 4 5 #include <cstdlib> 6 #include <cstring> 7 #include <algorithm> 8 #include <cmath> 9 10 #include <queue> 11 #include <vector> 12 #include <map> 13 #include <set> 14 #include <stack> 15 #include <list> 16 17 typedef unsigned int uint; 18 typedef long long int ll; 19 typedef unsigned long long int ull; 20 typedef double db; 21 typedef long double ldb; 22 23 using namespace std; 24 25 inline int getint() 26 { 27 int res=0; 28 char c=getchar(); 29 bool mi=false; 30 while(c<'0' || c>'9') mi=(c=='-'),c=getchar(); 31 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); 32 return mi ? -res : res; 33 } 34 inline ll getll() 35 { 36 ll res=0; 37 char c=getchar(); 38 bool mi=false; 39 while(c<'0' || c>'9') mi=(c=='-'),c=getchar(); 40 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); 41 return mi ? -res : res; 42 } 43 44 //============================================================================== 45 //============================================================================== 46 //============================================================================== 47 //============================================================================== 48 49 50 struct edge 51 { int in;edge*nxt; }; 52 int ecnt=4000; edge*et; edge*eds[305000]; 53 void addedge(int a,int b) 54 { 55 if(ecnt==4000) { et=new edge[4000]; ecnt=0; } 56 et->in=b; et->nxt=eds[a]; eds[a]=et++; ecnt++; 57 } 58 #define FOREACH_EDGE(i,x) for(edge*i=eds[x];i;i=i->nxt) 59 60 int n,m; 61 int q[305000]; 62 63 int f[305000]; //father of node. 64 int ch[305000],chtot; //chain of node. 65 int ct[305000]; //amount of chain nodes. 66 int cb[305000]; //base pointer of chain in segTree. 67 int h[305000]; //head of chain. 68 int loc[305000]; //location of node. 69 int dep[305000]; 70 int Build(int x) 71 { 72 int mx=0,mxp=-1,sum=0; 73 FOREACH_EDGE(e,x) 74 if(e->in!=f[x]) 75 { 76 int s=e->in; 77 dep[s]=dep[x]+1; 78 f[s]=x; 79 int v=Build(s); 80 sum+=v; 81 if(v>mx) mx=v,mxp=s; 82 } 83 84 if(mxp==-1) { ch[x]=chtot++; loc[x]=0; } 85 else { ch[x]=ch[mxp]; loc[x]=loc[mxp]+1; } 86 h[ch[x]]=x; 87 ct[ch[x]]++; 88 89 return sum+1; 90 } 91 92 int getlca(int a,int b) 93 { 94 while(ch[a]!=ch[b]) 95 { 96 if(dep[h[ch[a]]]<dep[h[ch[b]]]) swap(a,b); 97 a=f[h[ch[a]]]; 98 } 99 return dep[a]>dep[b] ? b : a; 100 } 101 102 //Segment Tree 103 int tag[1205000]; 104 int cl,cr,cv=1; 105 void Change(int x=1,int l=0,int r=n-1) 106 { 107 if(cl<=l && r<=cr) { tag[x]+=cv; return ; } 108 int mid=(l+r)>>1; 109 if(mid>=cl) Change(x<<1,l,mid); 110 if(mid<cr) Change(x<<1|1,mid+1,r); 111 } 112 int Query(int p) //single point query 113 { 114 int l=0,r=n-1,x=1; 115 ll res=0; 116 while(l!=r) 117 { 118 res+=tag[x]; 119 int mid=(l+r)>>1; 120 if(p<=mid) { r=mid; x<<=1; } 121 else { l=mid+1; x<<=1; x|=1; } 122 } 123 res+=tag[x]; 124 return res; 125 } 126 127 void addpath(int a,int fa) //directly add head and tail.Sub when counting. 128 { 129 while(ch[a]!=ch[fa]) 130 { 131 cl=loc[a]; 132 cr=cb[ch[a]]+ct[ch[a]]-1; 133 if(cl<=cr) Change(); 134 a=f[h[ch[a]]]; 135 } 136 cl=loc[a]; 137 cr=loc[fa]; 138 Change(); 139 } 140 141 int res[305000]; 142 143 int main() 144 { 145 n=getint(); 146 for(int i=0;i<n;i++) q[i]=getint()-1; 147 148 for(int i=0;i<n-1;i++) 149 { 150 int a=getint()-1; 151 int b=getint()-1; 152 addedge(a,b); addedge(b,a); 153 } 154 f[0]=0; dep[0]=0; 155 156 Build(0); 157 158 int s=0; 159 for(int i=0;i<chtot;i++) 160 cb[i]=s,s+=ct[i]; 161 162 for(int i=0;i<n;i++) 163 loc[i]+=cb[ch[i]]; 164 165 for(int i=1;i<n;i++) 166 { 167 int a=q[i-1]; 168 int b=q[i]; 169 int lca=getlca(a,b); 170 if(lca==a) { addpath(b,lca); } 171 else if(lca==b) { addpath(a,lca); } 172 else 173 { 174 addpath(a,lca); 175 addpath(b,lca); 176 res[lca]--; 177 } 178 res[b]--; 179 } 180 181 for(int i=0;i<n;i++) printf("%d\n",res[i]+Query(loc[i])); 182 183 return 0; 184 }
View Code
要求支持树上一条链上的所有点点权加一.
怪不得都说HLD好写=.=真的不难写.....速度比倍增快一个档次.....
AC BZOJ1036 树链
1 #include <cstdio> 2 #include <iostream> 3 4 #include <cstdlib> 5 #include <cstring> 6 #include <algorithm> 7 #include <cmath> 8 9 #include <queue> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <list> 15 16 typedef unsigned int uint; 17 typedef long long int ll; 18 typedef unsigned long long int ull; 19 typedef double db; 20 21 using namespace std; 22 23 inline int getint() 24 { 25 int res=0; 26 char c=getchar(); 27 bool mi=false; 28 while(c<'0' || c>'9') mi=(c=='-'),c=getchar(); 29 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar(); 30 return mi ? -res : res; 31 } 32 33 34 const int INF=(1<<30)-1; 35 36 int n; 37 38 39 int a[30050]; 40 41 42 //Segment Tree 43 ll sum[240000]; 44 int mx[240000]; 45 46 void update(const int&x) 47 { 48 sum[x]=sum[x<<1]+sum[x<<1|1]; 49 mx[x]=max(mx[x<<1],mx[x<<1|1]); 50 } 51 52 void Build(const int&x=1,const int&l=0,const int&r=n-1) 53 { 54 if(l==r) { mx[x]=sum[x]=a[l]; return ; } 55 int mid=(l+r)>>1; 56 Build(x<<1,l,mid); 57 Build(x<<1|1,mid+1,r); 58 update(x); 59 } 60 61 int cp,cv; 62 void Change(const int&x=1,const int&l=0,const int&r=n-1) 63 { 64 if(cp<l || r<cp) return ; 65 if(l==r) { mx[x]=sum[x]=cv; return ; } 66 int mid=(l+r)>>1; 67 Change(x<<1,l,mid); 68 Change(x<<1|1,mid+1,r); 69 update(x); 70 } 71 72 int ql,qr; 73 int QueryMax(const int&x=1,const int&l=0,const int&r=n-1) 74 { 75 if(qr<l || r<ql) return -INF; 76 if(ql<=l && r<=qr) return mx[x]; 77 int mid=(l+r)>>1; 78 return max( 79 QueryMax(x<<1,l,mid), 80 QueryMax(x<<1|1,mid+1,r)); 81 } 82 ll QuerySum(int x=1,int l=0,int r=n-1) 83 { 84 if(qr<l || r<ql) return 0; 85 if(ql<=l && r<=qr) return sum[x]; 86 int mid=(l+r)>>1; 87 return QuerySum(x<<1,l,mid) + QuerySum(x<<1|1,mid+1,r); 88 } 89 90 //End of Segment Tree 91 92 struct edge 93 { 94 int in; 95 edge*nxt; 96 }pool[80000]; 97 edge*et=pool; 98 edge*eds[30050]; 99 void addedge(int a,int b) 100 { 101 et->in=a; et->nxt=eds[b]; eds[b]=et++; 102 et->in=b; et->nxt=eds[a]; eds[a]=et++; 103 } 104 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt) 105 106 int c[30050],ctot; //chain code 107 int h[30050]; //head node of chain this node stands 108 bool t[30050]; //is this node a tail of a chain? 109 int f[30050]; //father node 110 int id[30050]; //location in segment 111 int dep[30050]; //depth 112 113 int DFS(int x,int cd) 114 { 115 dep[x]=cd; 116 int sum=0; 117 int m=0; 118 int p=-1; 119 FOREACH_EDGE(i,x) 120 if(i->in!=f[x]) 121 { 122 f[i->in]=x; 123 int h=DFS(i->in,cd+1); 124 sum+=h; 125 if(m<h) 126 { 127 m=h; 128 p=i->in; 129 } 130 } 131 132 if(p==-1) c[x]=ctot++,t[x]=true; //start a new chain 133 else c[x]=c[p]; //Insert this node to a chain 134 135 return sum+1; 136 } 137 138 inline int GetMax(int a,int b) 139 { 140 int res=-INF; 141 while(c[a]!=c[b]) 142 { 143 if(dep[h[c[a]]]<dep[h[c[b]]]) swap(a,b); 144 int&top=h[c[a]]; 145 ql=id[a]; 146 qr=id[top]; 147 res=max(res,QueryMax()); 148 a=f[top]; 149 } 150 151 ql=min(id[a],id[b]); 152 qr=max(id[a],id[b]); 153 res=max(res,QueryMax()); 154 155 return res; 156 } 157 158 inline ll GetSum(int a,int b) 159 { 160 ll res=0; 161 while(c[a]!=c[b]) 162 { 163 if(dep[h[c[a]]]<dep[h[c[b]]]) swap(a,b); 164 int&top=h[c[a]]; 165 ql=id[a]; 166 qr=id[top]; 167 res+=QuerySum(); 168 a=f[top]; 169 } 170 171 ql=min(id[a],id[b]); 172 qr=max(id[a],id[b]); 173 res+=QuerySum(); 174 175 return res; 176 } 177 178 inline void Edit(int a,ll p) 179 { 180 cp=id[a]; 181 cv=p; 182 Change(); 183 } 184 185 186 int main() 187 { 188 n=getint(); 189 for(int i=0;i<n-1;i++) 190 addedge(getint()-1,getint()-1); 191 192 f[0]=0; 193 DFS(0,0); 194 195 //assign nodes to the segment tree 196 int base=0; 197 for(int i=0;i<n;i++) 198 if(t[i]) 199 { 200 int x=i; 201 while(true) 202 { 203 id[x]=base++; 204 if(c[f[x]]==c[x] && x!=0) x=f[x]; 205 else break; 206 } 207 h[c[x]]=x; 208 } 209 210 for(int i=0;i<n;i++) 211 a[id[i]]=getint(); 212 213 Build(); 214 215 //deal all query 216 int q=getint(); 217 for(int d=0;d<q;d++) 218 { 219 char inp[8]; 220 scanf("%s",inp); 221 222 switch(inp[3]) 223 { 224 case 'X': //QMAX 225 { 226 int l=getint()-1; 227 int r=getint()-1; 228 printf("%d\n",GetMax(l,r)); 229 } 230 break; 231 case 'M': //QSUM 232 { 233 int l=getint()-1; 234 int r=getint()-1; 235 printf("%lld\n",GetSum(l,r)); 236 } 237 break; 238 case 'N': //CHANGE 239 { 240 int p=getint()-1; 241 int v=getint(); 242 Edit(p,v); 243 } 244 break; 245 default:break; 246 } 247 248 } 249 250 return 0; 251 }
View Code
写树链的大致思路:
1.线段树.
一棵全局线段树.......虽然牺牲了常数...但是至少不用去动态开树了=w=
2.构造轻重边.
这个是重点.
首先DFS记下: 1.父节点 2.所属链号 3.节点是所属链的第几个点.
顺便求出: 1.节点深度 2.每条链的长度(结点个数) 3.每条链的链头(深度最小的节点).
如果当前节点是叶节点,那么新开一条链.
如果当前节点不是叶节点,那么此节点所树链为节点最多的子树的根所属的链.
然后在DFS之外,我们可以通过链的长度来分配全局线段树的连续空间.
具体的假设链 $i$ 的节点数为 $t(i)$ 那么链 $i$ 线段树所维护的序列中,
区间 ${ [\; t(i-1)+t(i-2)+...+t(0)\; ,\; t(i)+t(i-1)+t(i-2)+t(0)\; ) }$ 就是链 $i$ 所管辖的区间.
然后按照"节点是所属链的第几个点"分配节点就好了.....
3.查询操作
查询(a,b)时保证a与b中a的所属链深度大于b的所属链深度.然后询问a到链头的值.
如果是边权....嗯.....我习惯把边权压到深度较大的那个节点......于是询问的时候:
链询问:询问a到链头的值; 然后再询问链头到它父节点(就是它本身,这个时候没必要理会)的值.
当a,b同属一条链时,还是令a的深度大于b的深度,然后询问a到b的前一个节点的值.
转载于:https://www.cnblogs.com/DragoonKiller/p/4295947.html
关于轻重边及树链剖分该怎么写...相关推荐
- [NOI2021 day1]轻重边(树链剖分),路径交点(矩阵行列式)
NOI 2021 day1 轻重边 description solution code 路径交点 description solution code 轻重边 description solution ...
- POJ - 1330 Nearest Common Ancestors(树上倍增/树链剖分求LCA)
题目链接:点击查看 题目大意:给出一棵有根树,我们需要求出两个点的lca 题目分析:因为题目说了是有根树,所以我们在建图的时候直接建有向图就好了,并且记录一下每个点的入度,建完图后找一下入度为0的点, ...
- 【模板】树链剖分 P3384
题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...
- [学习笔记]树链剖分
基本思想 树链剖分一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每条边属于且只属于一条链,然后再通过数据结构来维护每一条链. 一些定义 树链:树上的路径. 剖分:把路径分类为重链和轻链 ...
- 树链剖分 讲解+模板+习题
今天我们来讲一下树链剖分 树链剖分是什么? 树链剖分是一种用来维护树上路径信息的在线方法,可以处理在线. 通常通过一种方法,将一棵树剖分成若干条链,然后通过数据结构(线段树,BIT等)去维护. 我们通 ...
- 树链剖分(入门学习)
学习博客:https://www.cnblogs.com/ivanovcraft/p/9019090.html 先来回顾两个问题: 1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模板题了 ...
- 【暖*墟】#树链剖分# 树链剖分学习与练习
树链剖分 树链剖分是一种优化,将树上最常经过的几条链划为重点,用线段树来优化区间修改和查询. 并且因为在一棵子树中dfs序是连续的,并且在任意一条重链上,dfs序也是连续的, 可以认为轻链是单点修改, ...
- 数据结构--树链剖分详解
数据结构--树链剖分详解 关于模板题---->传送门 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将 ...
- 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习
LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...
最新文章
- nodejs这个过程POST求
- F#中的异步和并行设计模式(三):代理
- java 与sql设置排序方法是_恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合...
- YunTable 0.1版正式发布!!!(转载)
- 汇编原理实验 --电话簿的实现
- vue-day04-vue前端交互
- 【翻译】Emmet(Zen Coding)官方文档 之七 一览表
- Python数据科学学习进阶
- python交互式编程在哪里_终于明了python交互式编程入门
- org.apache.hadoop.hbase.PleaseHoldException: Master is initializing
- hive 旧版本版本下载
- FPS 游戏实现GDI透视
- mysql 8.0 初识
- matlab批量修改文件名字
- 《Python语言程序设计基础》——读书笔记
- 利用预测分析改进欠款催收策略,控制欺诈风险和信贷风险
- 较为详细的记录总结TensorRT的python接口的使用,环境配置,模型转换和静态动态模型推理
- 打造黑苹果(三)COMS BIOS 设置
- unity 标准资源包中的围绕旋转摄像机
- print(f‘‘)的用法