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

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