MySQL 的日誌:binlog
阿新 • • 發佈:2021-12-21
初學樹分治的學習筆記。
分治本質上都是一樣的,就是要把原問題分割成幾個規模更小的問題分別求解然後再合併上去。而由於樹它本身具有很強的遞迴特性(籠統的說就是樹的部分還是樹),於是就使得樹上分治成為可能。
樹分治一般遵循以下步驟:
第一步,把樹中所有節點全部找出來,然後把它們近乎於暴力地統計一遍答案(此步驟一般是 \(O(N)/O(NlogN)\)),而且此步驟只統計所有經過根節點的路徑;第二步就是找到當前這棵樹的重心(這樣可以使得分治下去的問題規模得到保障從而保證複雜度),然後遞迴處理即可。整體複雜度是\(O(NlogN)\)左右。
按照這個思路就可以寫這道題了。
一如既往,萬事勝意#include<cstdio> #include<cstring> #include<algorithm> //#define zczc #define ll long long using namespace std; const int N=40010; const int maxn=1e9; using namespace std; inline void read(int &wh){ wh=0;int f=1;char w=getchar(); while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();} while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();} wh*=f;return; } inline int max(int s1,int s2){ return s1<s2?s2:s1; } int m,want; struct edge{ int t,v,next; }e[N<<1]; int head[N],esum; inline void add(int fr,int to,int val){ esum++; e[esum].t=to; e[esum].v=val; e[esum].next=head[fr]; head[fr]=esum; return; } ll ans; bool vis[N]; //solve pairs int cnt,dis[N]; void dfs(int wh,int fa,int ndis){ dis[++cnt]=ndis; for(int i=head[wh],th;i;i=e[i].next){ th=e[i].t; if(vis[th]||th==fa)continue; dfs(th,wh,ndis+e[i].v); } } int work(int wh,int val){ //init cnt=0; dfs(wh,0,val); sort(dis+1,dis+cnt+1); int an=0; for(int i=cnt,j=0;i;i--){ //對於dis[i]找到有多少個符合條件的j與之對應 while(j==0||(j<=cnt&&dis[j]+dis[i]<=want))j++;j--; an+=j;if(i<=j)an--; } return an/2; } //get new root int hsize;//whole size int amax;//ans maxn int nroot,size[N]; void dfs2(int wh,int fa){ size[wh]=1; int nmax=0; for(int i=head[wh],th;i;i=e[i].next){ th=e[i].t; if(vis[th]||th==fa)continue; dfs2(th,wh); size[wh]+=size[th]; nmax=max(nmax,size[th]); } nmax=max(nmax,hsize-size[wh]); if(nmax<amax){ amax=nmax; nroot=wh; } return; } void solve_root(int wh){ amax=maxn; hsize=size[wh]; dfs2(wh,0); return; } void solve(int wh){ //printf("now:%d %d\n",wh,ans); ans+=work(wh,0); vis[wh]=true; for(int i=head[wh],th;i;i=e[i].next){ th=e[i].t; if(vis[th])continue; ans-=work(th,e[i].v); solve_root(th); solve(th); } return; } void init(){ memset(head,0,sizeof(head)); esum=0; memset(vis,0,sizeof(vis)); ans=0; return; } signed main(){ #ifdef zczc freopen("in.txt","r",stdin); #endif read(m); int s1,s2,s3; for(int i=1;i<m;i++){ read(s1);read(s2);read(s3); add(s1,s2,s3);add(s2,s1,s3); } read(want); hsize=m; solve(1); printf("%lld\n",ans); return 0; }