边分治学习笔记
對于某些點分治不太好合并兩條鏈的信息的題,可以考慮使用邊分治;
邊分治時的主要思想跟點分治一樣,一直去找某個重心,把一棵樹不斷化成更小的部分,邊分治需要找的這個重心在邊上,使得去掉這條邊過后兩邊剩的點的差最小,寫法跟點分治都差不多,但是邊分治會被菊花圖這樣的樹給卡成\(n^2\),所以在邊分治之前要重構原樹,把原樹變成一棵二叉樹,具體做法就是新建虛節點然后把真實兒子放在虛二叉樹的葉子節點上,這樣做就沒有數據能把邊分治卡下來,空間參考堆式線段樹的算法,變成了\(4n\)的樣子;
邊分治每次把當前聯通快分成了兩坨,計算貢獻也比點分治方便多了;
以下邊分治部分的代碼自己yy的,可能寫丑了或者傻逼自帶大常數了;
例題 BZOJ#2870
/*Name: BZOJ#2870Author: CIaoDate: 09/03/19 17:08Description: 邊分治 */ #include<bits/stdc++.h> #define Fst first #define Snd second #define RG register #define mp make_pair #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long LL; typedef long double LD; typedef unsigned int UI; typedef unsigned long long ULL; template<typename T> inline void read(T& x) {char c = getchar();bool f = false;for (x = 0; !isdigit(c); c = getchar()) {if (c == '-') {f = true;}}for (; isdigit(c); c = getchar()) {x = x * 10 + c - '0';}if (f) {x = -x;} } template<typename T, typename... U> inline void read(T& x, U& ... y) {read(x), read(y...); } const int INF=65536+1,N=2e5+10; int n,p=1,O,Ed,TOT,size,root,MAXV,TMP; int head[N],A[N],V[N],num[N]; LL ANS; bool G[N],No[N<<1]; vector<int> E[N]; struct Edge {int to,last,w;Edge () {}Edge (int a,int b,int c) :to(a),last(b),w(c) {} }edge[N<<1]; void ADD(int a,int b,int c) {edge[++p]=Edge(b,head[a],c); head[a]=p;edge[++p]=Edge(a,head[b],c); head[b]=p; } void Build(int l,int r,int f) {if(l>r) return;if(l==r) {ADD(f,V[l],1);return;}int mid=l+r>>1,rt=++n; A[rt]=A[f];ADD(f,rt,0);Build(l,mid,rt); Build(mid+1,r,rt); } void DFS(int u,int f) {int cnt=0;for(int i=0;i<(int)E[u].size();++i) if(E[u][i]!=f) V[++cnt]=E[u][i];int mid=1+cnt>>1;Build(1,mid,u); Build(mid+1,cnt,u);for(int i=0;i<(int)E[u].size();++i) if(E[u][i]!=f) DFS(E[u][i],u); } void GetEdge(int u,int f) {num[u]=1;for(int i=head[u];i;i=edge[i].last) {int v=edge[i].to;if(!No[i]&&v!=f) {GetEdge(v,u);num[u]+=num[v];}}for(int i=head[u];i;i=edge[i].last) {int v=edge[i].to;if(!No[i]&&v!=f) {if(MAXV>abs(TOT-num[v]*2)) {root=u; Ed=i;MAXV=abs(TOT-num[v]*2);}}} } int cnt,tot; struct Data {int val,dis; }F[N],P[N]; void Getdis(int u,int f,int val,int dis) {val=min(val,A[u]);if(G[u]) {F[++cnt]=(Data){val,dis+1};ANS=max(ANS,1ll*(dis+1)*val);}for(int i=head[u];i;i=edge[i].last) {int v=edge[i].to;if(!No[i]&&v!=f) Getdis(v,u,val,dis+edge[i].w);} } void Calc(int u,int f,int val,int dis) {val=min(val,A[u]);if(G[u]) P[++tot]=(Data){val,dis+TMP};for(int i=head[u];i;i=edge[i].last) {int v=edge[i].to;if(!No[i]&&v!=f) Calc(v,u,val,dis+edge[i].w);} } bool cmp(Data A,Data B) {return A.val==B.val?A.dis<B.dis:A.val<B.val; } void Solve() {if(!cnt||!tot) return;sort(F+1,F+cnt+1,cmp); sort(P+1,P+tot+1,cmp);for(int i=cnt-1;i;--i) F[i].dis=max(F[i].dis,F[i+1].dis);int now=1;for(int i=1;i<=tot;++i) {while(now!=cnt&&F[now].val<P[i].val) ++now;if(F[now].val>=P[i].val) ANS=max(ANS,1ll*P[i].val*(P[i].dis+F[now].dis));} } void DAC(int u1,int e) {if(e==-1) return;int u2=edge[e].to; No[e]=No[e^1]=true; TMP=edge[e].w;cnt=tot=0; Getdis(u1,0,INF,0); Calc(u2,0,INF,0); Solve();cnt=tot=0; Getdis(u2,0,INF,0); Calc(u1,0,INF,0); Solve();int S1=TOT-num[u2],S2=num[u2];root=u1; Ed=-1; MAXV=S1+1; TOT=S1; GetEdge(u1,0); DAC(root,Ed);root=u2; Ed=-1; MAXV=S2+1; TOT=S2; GetEdge(u2,0); DAC(root,Ed); } //#define rua int main() { // ios::sync_with_stdio(false); #ifdef rua #endifread(n);for(int i=1;i<=n;++i) read(A[i]),G[i]=true;for(int i=1;i<n;++i) {int u,v; read(u,v);E[u].push_back(v); E[v].push_back(u);}DFS(1,0);root=1; Ed=-1; MAXV=n+1; TOT=n; GetEdge(1,0);DAC(root,Ed);printf("%lld\n",ANS);return 0; }轉載于:https://www.cnblogs.com/ak12/p/10502106.html
總結
- 上一篇: 转汇编
- 下一篇: Web前端-JavaScript基础教程