倍增
倍增
倍增最广泛的应用就是求LCA了吧,反正我是从这里入坑的qwq
最近公共祖先:https://www.luogu.org/problemnew/show/P3379
1 # include <cstdio> 2 # include <iostream> 3 4 using namespace std; 5 6 int f,n,m,s,x,xx,b,y,h=0; 7 char c; 8 int firs[500007]={0},dep[500007]={0},F[500007][22]={0}; 9 bool vis[500007]={0}; 10 11 struct edge 12 { 13 int y; 14 int Nex; 15 }g[1000007]={0}; 16 17 int readd() 18 { 19 xx=0,f=1; 20 c=getchar(); 21 while (! isdigit(c)) 22 { 23 if(c=='-') f=-f; 24 c=getchar(); 25 } 26 while (isdigit(c)) 27 { 28 xx=(xx<<3)+(xx<<1)+(c^48); 29 c=getchar(); 30 } 31 return xx*f; 32 } 33 34 void add(int x,int y) 35 { 36 g[++h].y=y; 37 g[h].Nex=firs[x]; 38 firs[x]=h; 39 } 40 41 void build(int x) 42 { 43 for (int i=firs[x];i;i=g[i].Nex) 44 { 45 int j=g[i].y; 46 if(!vis[j]) 47 { 48 dep[j]=dep[x]+1; 49 F[j][0]=x; 50 vis[j]=true; 51 for (int z=1;z<=21;z++) 52 F[j][z]=F[ F[j][z-1] ][z-1]; 53 build(j); 54 } 55 } 56 } 57 58 int flca(int x,int y) 59 { 60 if(dep[x]>dep[y]) 61 swap(x,y); 62 for (int i=20;i>=0;i--) 63 { 64 if(dep[x]<=dep[y]-(1<<i)) 65 y=F[y][i]; 66 } 67 if(x==y) return x; 68 for (int i=20;i>=0;i--) 69 { 70 if(F[x][i]==F[y][i]) 71 continue; 72 x=F[x][i]; 73 y=F[y][i]; 74 } 75 return F[x][0]; 76 } 77 78 int main() 79 { 80 n=readd(); 81 m=readd(); 82 s=readd(); 83 for (int i=1;i<n;i++) 84 { 85 x=readd(); 86 y=readd(); 87 add(x,y); 88 add(y,x); 89 } 90 dep[s]=1; 91 vis[s]=true; 92 build(s); 93 for (int i=1;i<=m;i++) 94 { 95 x=readd(); 96 y=readd(); 97 printf("%d\n",flca(x,y)); 98 } 99 return 0; 100 }
跑路:https://www.luogu.org/problemnew/show/P1613
货车运输:https://www.luogu.org/problemnew/show/P1967
题意概述:最大瓶颈路。
当时做的时候可没有听说过这么简单又清晰的名词。
发现这个图中有很多边是没有用的,因为不要求什么总路程最小之类的加法操作,只是取min,那么可以没有任何顾虑的绕很多路,也就是说,如果两个点之间有一条最小值为10的要绕好多别的点的路,它也是比直接相连的一条限重为5的路要优的,有没有想到什么算法呢?最小生成树。不过这道题是最大生成树。想到这个之后就非常简单了,只不过是在求lca的时候顺便维护一下最小值就行了。也可以用Kruscal重构树,也不错。
1 // luogu-judger-enable-o2 2 # include <cstdio> 3 # include <iostream> 4 # include <algorithm> 5 # include <cmath> 6 # define R register 7 8 using namespace std; 9 10 struct edge 11 { 12 int x,y,cos; 13 int Nex; 14 }; 15 16 struct L 17 { 18 int lc,ma; 19 }; 20 21 int szr,dep[10005]={0},firs[10005]={0},f[10005]={0}; 22 int Max,j,m,n,x,y,xx,ff,fx,fy,q,h=0; 23 char cc; 24 bool vis[10005]={false}; 25 edge a[50005],g[20010]; 26 L F[10005][14]={0}; 27 28 int father (int x) 29 { 30 if(x!=f[x]) return f[x]=father(f[x]); 31 return x; 32 } 33 34 int readd() 35 { 36 xx=0; 37 ff=1; 38 cc=getchar(); 39 while (!isdigit(cc)) 40 { 41 ff=-ff; 42 cc=getchar(); 43 } 44 while (isdigit(cc)) 45 { 46 xx=(xx<<3)+(xx<<1)+(cc^48); 47 cc=getchar(); 48 } 49 return xx*ff; 50 } 51 52 bool cmp(edge a,edge b) 53 { 54 return a.cos>b.cos; 55 } 56 57 void add(int x,int y,int cos) 58 { 59 g[++h].y=y; 60 g[h].cos=cos; 61 g[h].Nex=firs[x]; 62 firs[x]=h; 63 } 64 65 void build(int x) 66 { 67 for (R int i=firs[x];i;i=g[i].Nex) 68 { 69 j=g[i].y; 70 if(!vis[j]) 71 { 72 dep[j]=dep[x]+1; 73 vis[j]=true; 74 F[j][0].lc=x; 75 F[j][0].ma=g[i].cos; 76 for (R int z=1;z<=13;z++) 77 { 78 F[j][z].ma=min(F[j][z-1].ma,F[F[j][z-1].lc][z-1].ma); 79 F[j][z].lc=F[ F[j][z-1].lc ][z-1].lc; 80 } 81 build(j); 82 } 83 } 84 } 85 86 int lca(int x,int y) 87 { 88 if(dep[x]>dep[y]) 89 swap(x,y); 90 for (R int i=13;i>=0;i--) 91 if(dep[x]<=dep[y]-(1<<i)) 92 y=F[y][i].lc; 93 if(x==y) return x; 94 for (R int i=13;i>=0;i--) 95 if(F[x][i].lc==F[y][i].lc) 96 continue; 97 else 98 { 99 x=F[x][i].lc; 100 y=F[y][i].lc; 101 } 102 return F[x][0].lc; 103 } 104 105 int lma(int x,int c) 106 { 107 Max=100009; 108 for (R int i=13;i>=0;i--) 109 { 110 if(dep[c]<=dep[x]-(1<<i)) 111 { 112 Max=min(Max,F[x][i].ma); 113 x=F[x][i].lc; 114 } 115 } 116 return Max; 117 } 118 119 int main() 120 { 121 n=readd(); 122 m=readd(); 123 for (R int i=1;i<=n;i++) 124 f[i]=i; 125 for (R int i=1;i<=m;i++) 126 { 127 a[i].x=readd(); 128 a[i].y=readd(); 129 a[i].cos=readd(); 130 } 131 sort(a+1,a+1+m,cmp); 132 for (R int i=1;i<=m;i++) 133 { 134 fx=a[i].x; 135 fy=a[i].y; 136 fx=father(fx); 137 fy=father(fy); 138 if(fx!=fy) 139 { 140 f[fy]=fx; 141 add(a[i].x,a[i].y,a[i].cos); 142 add(a[i].y,a[i].x,a[i].cos); 143 } 144 } 145 for (R int i=1;i<=n;i++) 146 if(f[i]==i) 147 { 148 vis[i]=true; 149 dep[i]=1; 150 build(i); 151 } 152 q=readd(); 153 for (R int i=1;i<=q;i++) 154 { 155 x=readd(); 156 y=readd(); 157 szr=lca(x,y); 158 if(szr==0)printf("-1\n"); 159 else 160 printf("%d\n",min(lma(x,szr),lma(y,szr))); 161 } 162 return 0; 163 }
之前码风比较清奇,喜欢用id做变量名。后来还换了ID.
开车旅行:https://www.luogu.org/problemnew/show/P1081
题意概述:好麻烦,没法概述,看链接吧。
这个题预处理是最麻烦的,考虑逆序插入点,保证找到的点一定在给定点的东边,因为Set用的不大好,就种了一棵平衡树。最近的点一定是前驱或后继,如果最近的是前驱,那么第二近的可能是后继或者前驱的前驱,反之亦然。一定要注意处理好这个部分,如果不存在的话一定要写上-1,否则后面会麻烦。倍增部分:$id[i][j]$表示从$i$点走$2^j$步走到的点的编号,如果不存在就是-1;再定义两个数组分别对应$id$数组表示走这么远时A走了多少,B走了多少。写了一晚上...补充:做了$16$年的初赛题以后学到了一个新的技巧,用排序+链表实现本题中平衡树的功能,感觉挺有意思的:首先把每个点压进结构体,记录一下它的位置,排序后连成链表,从原位置最小的那个点开始找,因为它是最左边的,所以其他的点必然都在它的右边啦,找到它所需要的答案(也就是它的左右两个相连点)后把它删掉后再找第二个点的答案,显然这个时候是不会找到不合法解的,以此类推.
1 # include <cstdio> 2 # include <iostream> 3 # include <set> 4 # include <cstdlib> 5 # include <map> 6 # define inf 1000000009 7 # define R register int 8 9 using namespace std; 10 11 const int maxn=100005; 12 int n,X0,m,ans; 13 int h[maxn],nex[maxn]; 14 int s[maxn],x[maxn],a[maxn],b[maxn]; 15 int id[maxn][18]; 16 long long al[maxn][18],bl[maxn][18]; 17 long long ansa,ansb,sa=0,sb=0; 18 map <int,int> M; 19 20 struct node 21 { 22 int n,r,v,s; 23 node *ch[2]; 24 void in (int x) 25 { 26 v=x; 27 n=s=1; 28 r=rand(); 29 ch[0]=ch[1]=NULL; 30 } 31 int cmp (int x) 32 { 33 if(x==v) return -1; 34 return x>v; 35 } 36 void update() 37 { 38 s=n; 39 if(ch[0]) s+=ch[0]->s; 40 if(ch[1]) s+=ch[1]->s; 41 } 42 }*roo,pool[maxn]; 43 44 node *newnode () 45 { 46 static int cnt=0; 47 return &pool[++cnt]; 48 } 49 50 void rotate(node *&n,int d) 51 { 52 node *k=n->ch[d^1]; 53 n->ch[d^1]=k->ch[d]; 54 k->ch[d]=n; 55 n->update(); 56 k->update(); 57 n=k; 58 } 59 60 void ins(node *&n,int x) 61 { 62 if(!n) n=newnode(),n->in(x); 63 else 64 { 65 int d=n->cmp(x); 66 if(d==-1) ++n->n; 67 else 68 { 69 ins(n->ch[d],x); 70 if(n->ch[d]->r > n->r) rotate(n,d^1); 71 } 72 n->update(); 73 } 74 } 75 76 int lef(node *&n,int x) 77 { 78 if(!n) return -inf; 79 if(n->v>=x) return lef(n->ch[0],x); 80 return max(n->v,lef(n->ch[1],x)); 81 } 82 83 int rig(node *&n,int x) 84 { 85 if(!n) return inf; 86 if(n->v<=x) return rig(n->ch[1],x); 87 return min(n->v,rig(n->ch[0],x)); 88 } 89 90 inline int read() 91 { 92 int x=0,f=1; 93 char c=getchar(); 94 while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); } 95 while (isdigit(c)) { x=(x<<3)+(x<<1)+(c^48); c=getchar(); } 96 return x*f; 97 } 98 99 void init() 100 { 101 int l,r; 102 M[inf]=-1; 103 M[-inf]=-1; 104 M[inf+1]=-1; 105 M[-inf-1]=-1; 106 ins(roo,inf); 107 ins(roo,inf+1); 108 ins(roo,-inf); 109 ins(roo,-inf-1); 110 for (int i=n;i>=1;--i) 111 { 112 ins(roo,h[i]); 113 l=lef(roo,h[i]); 114 r=rig(roo,h[i]); 115 if(l<=-inf) 116 { 117 if(r>=inf) a[i]=b[i]=-1; 118 else 119 { 120 b[i]=M[r]; 121 r=rig(roo,r); 122 if(r<inf) a[i]=M[r]; 123 else a[i]=-1; 124 } 125 } 126 else 127 if(r>=inf) 128 { 129 if(l<=-inf) a[i]=b[i]=-1; 130 else 131 { 132 b[i]=M[l]; 133 l=lef(roo,l); 134 if(l>-inf) a[i]=M[l]; 135 else a[i]=-1; 136 } 137 } 138 else 139 if(h[i]-l<=r-h[i]) 140 { 141 b[i]=M[l]; 142 l=lef(roo,l); 143 if(l<=-inf) a[i]=M[r]; 144 else 145 if(h[i]-l<=r-h[i]) 146 a[i]=M[l]; 147 else 148 a[i]=M[r]; 149 } 150 else 151 { 152 b[i]=M[r]; 153 r=rig(roo,r); 154 if(r>=inf) a[i]=M[l]; 155 else 156 if(h[i]-l<=r-h[i]) 157 a[i]=M[l]; 158 else 159 a[i]=M[r]; 160 } 161 } 162 } 163 164 int ab (int a) 165 { 166 if(a<0) return -a; 167 return a; 168 } 169 170 void solve (int s,int x) 171 { 172 sa=sb=0; 173 long long Sum=0; 174 for (int i=17;i>=0;--i) 175 { 176 if(id[s][i]==-1) continue; 177 if(Sum+al[s][i]+bl[s][i]>x) continue; 178 Sum+=al[s][i]+bl[s][i]; 179 sa+=al[s][i]; 180 sb+=bl[s][i]; 181 s=id[s][i]; 182 if(s==-1) break; 183 } 184 } 185 186 void bz() 187 { 188 for (int i=1;i<=n;++i) 189 { 190 id[i][0]=a[i]; 191 if(a[i]==-1) 192 { 193 id[i][1]=-1; 194 continue; 195 } 196 al[i][0]=ab(h[i]-h[a[i]]); 197 bl[i][0]=0; 198 id[i][1]=b[ a[i] ]; 199 if(id[i][1]==-1) continue; 200 al[i][1]=ab(h[i]-h[ a[i] ]); 201 bl[i][1]=ab(h[ a[i] ]-h[ b[ a[i] ] ]); 202 } 203 for (int i=n;i>=1;--i) 204 for (int j=2;j<=17;++j) 205 { 206 if(id[i][j-1]==-1) 207 { 208 id[i][j]=-1; 209 continue; 210 } 211 id[i][j]=id[ id[i][j-1] ][j-1]; 212 if(id[i][j]==-1) continue; 213 al[i][j]=al[ id[i][j-1] ][j-1]+al[i][j-1]; 214 bl[i][j]=bl[ id[i][j-1] ][j-1]+bl[i][j-1]; 215 } 216 } 217 218 int main() 219 { 220 scanf("%d",&n); 221 for (R i=1;i<=n;++i) 222 h[i]=read(),M[ h[i] ]=i; 223 scanf("%d%d",&X0,&m); 224 for (R i=1;i<=m;++i) 225 s[i]=read(),x[i]=read(); 226 init(); 227 bz(); 228 solve(1,X0); 229 ansa=sa; 230 ansb=sb; 231 ans=1; 232 for (R i=2;i<=n;++i) 233 { 234 solve(i,X0); 235 if(sb!=0) 236 { 237 if(sa*ansb<sb*ansa) 238 { 239 ansa=sa; 240 ansb=sb; 241 ans=i; 242 } 243 else if(sa*ansb==sb*ansa) 244 { 245 if(h[ans]<h[i]) ans=i; 246 } 247 } 248 else 249 { 250 if(ansb!=0) continue; 251 else 252 { 253 if(h[ans]<h[i]) ans=i; 254 } 255 } 256 } 257 printf("%d\n",ans); 258 for (R i=1;i<=m;++i) 259 { 260 solve(s[i],x[i]); 261 printf("%lld %lld\n",sa,sb); 262 } 263 return 0; 264 }
聚会:https://www.luogu.org/problemnew/show/P4281
题意概述:多组询问,给定无权树上三个点,找到一个点使得三点到这一点的总距离之和最小.$n,m<=500000$
今天考试考到了这个题,打表猜出了规律,现在尝试证明一下。
首先这个点肯定是某一对点的$LCA$,为什么呢?如果题目是问两个点,其中一个答案就是它们的$LCA$,扩展到三个点的情况:
看一看三点的$LCA$有多少种情况:开始随意指定$A,B$两点求出$LCA$,这时$C$点的放置有两种方法:1.接在$LCA$的子树内,那么它和$A$,$B$中至少一个的$LCA$还是之前那个$LCA$; 2.接在$LCA$的子树外面:那么它和$A,B$两点的$LCA$就是相同的了.事实上这两种情况没有太大差别,画出来都是这样子:
·三对$LCA$在同一点上,那么显然答案就是这个点,否则就会出现一个点的路程少了$X$,另两个点又各多了$X$的情况;
·$LCA$有两种位置:答案是深度更深的那个(也就是不同的那个),如果答案在它下面,那么有两个点要多走,不合理;如果答案在它上面,那么答案每上升一步,$A,B$两点就要多走一步,$C$却只能少走一步.
·$LCA$有三种取值:不存在;
注意卡常;
1 # include <cstdio> 2 # include <iostream> 3 # include <cstring> 4 # include <algorithm> 5 # include <string> 6 # include <cmath> 7 # define R register int 8 9 using namespace std; 10 11 const int maxn=500005; 12 int n,m,x,y,l,a,b,c,h,firs[maxn],dep[maxn],f[maxn][21],ans,co,pos,l1,l2,l3,lg[maxn]; 13 struct edge 14 { 15 int too,nex; 16 }g[maxn<<1]; 17 18 int read () 19 { 20 int x=0; 21 char c=getchar(); 22 while(!isdigit(c)) c=getchar(); 23 while(isdigit(c)) { x=(x<<3)+(x<<1)+(c^48); c=getchar(); } 24 return x; 25 } 26 27 void dfs (int x) 28 { 29 int j; 30 for (R i=firs[x];i;i=g[i].nex) 31 { 32 j=g[i].too; 33 if(dep[j]) continue; 34 dep[j]=dep[x]+1; 35 f[j][0]=x; 36 for (R k=1;k<=lg[ dep[j] ];++k) 37 f[j][k]=f[ f[j][k-1] ][k-1]; 38 dfs(j); 39 } 40 } 41 42 int lca (int x,int y) 43 { 44 if(dep[x]>dep[y]) swap(x,y); 45 for (R i=lg[ dep[y] ];i>=0;--i) 46 if(dep[y]-(1<<i)>=dep[x]) y=f[y][i]; 47 if(x==y) return x; 48 for (R i=lg[ dep[x] ];i>=0;--i) 49 { 50 if(f[x][i]==f[y][i]) continue; 51 x=f[x][i]; 52 y=f[y][i]; 53 } 54 return f[x][0]; 55 } 56 57 int dis (int a,int b) 58 { 59 int l=lca(a,b); 60 return dep[a]+dep[b]-2*dep[l]; 61 } 62 63 void add (int x,int y) 64 { 65 g[++h].too=y; 66 g[h].nex=firs[x]; 67 firs[x]=h; 68 } 69 70 int main() 71 { 72 n=read(),m=read(); 73 for (R i=2;i<=n;++i) 74 lg[i]=lg[i>>1]+1; 75 for (R i=1;i<n;++i) 76 { 77 x=read(),y=read(); 78 add(x,y); 79 add(y,x); 80 } 81 dep[1]=1; 82 dfs(1); 83 for (R i=1;i<=m;++i) 84 { 85 a=read(),b=read(),c=read(); 86 l1=lca(a,b); 87 l2=lca(a,c); 88 l3=lca(b,c); 89 if(l1==l2) l=l3,swap(a,c); 90 if(l2==l3) l=l1; 91 if(l1==l3) l=l2,swap(b,c); 92 printf("%d %d\n",l,dep[a]+dep[b]-2*dep[l]+dis(c,l)); 93 } 94 return 0; 95 }
---shzr