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 }
题解好神......两两求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 }
要求支持树上一条链上的所有点点权加一.
怪不得都说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 }
写树链的大致思路:
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的前一个节点的值.