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

关于轻重边及树链剖分该怎么写...相关推荐

  1. [NOI2021 day1]轻重边(树链剖分),路径交点(矩阵行列式)

    NOI 2021 day1 轻重边 description solution code 路径交点 description solution code 轻重边 description solution ...

  2. POJ - 1330 Nearest Common Ancestors(树上倍增/树链剖分求LCA)

    题目链接:点击查看 题目大意:给出一棵有根树,我们需要求出两个点的lca 题目分析:因为题目说了是有根树,所以我们在建图的时候直接建有向图就好了,并且记录一下每个点的入度,建完图后找一下入度为0的点, ...

  3. 【模板】树链剖分 P3384

    题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...

  4. [学习笔记]树链剖分

    基本思想 树链剖分一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每条边属于且只属于一条链,然后再通过数据结构来维护每一条链. 一些定义 树链:树上的路径. 剖分:把路径分类为重链和轻链 ...

  5. 树链剖分 讲解+模板+习题

    今天我们来讲一下树链剖分 树链剖分是什么? 树链剖分是一种用来维护树上路径信息的在线方法,可以处理在线. 通常通过一种方法,将一棵树剖分成若干条链,然后通过数据结构(线段树,BIT等)去维护. 我们通 ...

  6. 树链剖分(入门学习)

    学习博客:https://www.cnblogs.com/ivanovcraft/p/9019090.html 先来回顾两个问题: 1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模板题了 ...

  7. 【暖*墟】#树链剖分# 树链剖分学习与练习

    树链剖分 树链剖分是一种优化,将树上最常经过的几条链划为重点,用线段树来优化区间修改和查询. 并且因为在一棵子树中dfs序是连续的,并且在任意一条重链上,dfs序也是连续的, 可以认为轻链是单点修改, ...

  8. 数据结构--树链剖分详解

    数据结构--树链剖分详解 关于模板题---->传送门 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将 ...

  9. 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习

    LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...

最新文章

  1. nodejs这个过程POST求
  2. F#中的异步和并行设计模式(三):代理
  3. java 与sql设置排序方法是_恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合...
  4. YunTable 0.1版正式发布!!!(转载)
  5. 汇编原理实验 --电话簿的实现
  6. vue-day04-vue前端交互
  7. 【翻译】Emmet(Zen Coding)官方文档 之七 一览表
  8. Python数据科学学习进阶
  9. python交互式编程在哪里_终于明了python交互式编程入门
  10. org.apache.hadoop.hbase.PleaseHoldException: Master is initializing
  11. hive 旧版本版本下载
  12. FPS 游戏实现GDI透视
  13. mysql 8.0 初识
  14. matlab批量修改文件名字
  15. 《Python语言程序设计基础》——读书笔记
  16. 利用预测分析改进欠款催收策略,控制欺诈风险和信贷风险
  17. 较为详细的记录总结TensorRT的python接口的使用,环境配置,模型转换和静态动态模型推理
  18. 打造黑苹果(三)COMS BIOS 设置
  19. unity 标准资源包中的围绕旋转摄像机
  20. print(f‘‘)的用法

热门文章

  1. onresize的应用--自适应弹窗
  2. Monotone Chain Convex Hull(单调链凸包)
  3. POJ 1724 ROADS(bfs最短路)
  4. mysql delete|删除 命令的注意点
  5. 标准exception类层次图
  6. 2012.02.17
  7. javascript专题汇总
  8. 奥巴马:乔布斯改变我们每个人看世界的方式
  9. pll制作分频器_PLL学习过程记录
  10. raspberry pi_在Raspberry Pi上使用Mathematica进行高级数学运算