BZOJ3697: 采药人的路径(点分治)
Description
采藥人的藥田是一個(gè)樹(shù)狀結(jié)構(gòu),每條路徑上都種植著同種藥材。
采藥人以自己對(duì)藥材獨(dú)到的見(jiàn)解,對(duì)每種藥材進(jìn)行了分類(lèi)。大致分為兩類(lèi),一種是陰性的,一種是陽(yáng)性的。
采藥人每天都要進(jìn)行采藥活動(dòng)。他選擇的路徑是很有講究的,他認(rèn)為陰陽(yáng)平衡是很重要的,所以他走的一定是兩種藥材數(shù)目相等的路徑。采藥工作是很辛苦的,所以他希望他選出的路徑中有一個(gè)可以作為休息站的節(jié)點(diǎn)(不包括起點(diǎn)和終點(diǎn)),滿足起點(diǎn)到休息站和休息站到終點(diǎn)的路徑也是陰陽(yáng)平衡的。他想知道他一共可以選擇多少種不同的路徑。
Input
第1行包含一個(gè)整數(shù)N。
接下來(lái)N-1行,每行包含三個(gè)整數(shù)a_i、b_i和t_i,表示這條路上藥材的類(lèi)型。
Output
輸出符合采藥人要求的路徑數(shù)目。
Sample Input
71 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1解題思路:
點(diǎn)分治要求在尋找到一條鏈時(shí)統(tǒng)計(jì)答案與重心在鏈的哪個(gè)位置無(wú)關(guān)。而顯然這道題如果枚舉重心為中轉(zhuǎn)站是錯(cuò)誤的,因?yàn)橐粭l鏈只被統(tǒng)計(jì)一次,而中心位置很可能是錯(cuò)誤的,所以我們需要修正這一點(diǎn),就是統(tǒng)計(jì)重心路徑上可能出現(xiàn)的中心位置。
換句話說(shuō),開(kāi)四個(gè)桶來(lái)記錄,分別記錄當(dāng)前子樹(shù)內(nèi)可能出現(xiàn)的中轉(zhuǎn)站(出現(xiàn)過(guò)的距離重復(fù),在差分的意義下說(shuō)明出現(xiàn)和為0的區(qū)間),另外一個(gè)就是之前子樹(shù)的答案,每次更新完合并桶就好了。
代碼:
?
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 const int N=100010; 6 struct pnt{ 7 int hd; 8 int dis; 9 int wgt; 10 bool vis; 11 }p[N]; 12 struct ent{ 13 int twd; 14 int lst; 15 int vls; 16 }e[N<<1]; 17 lnt f[N<<1][2],g[N<<1][2]; 18 int has[N<<1]; 19 int n; 20 lnt top; 21 int cnt; 22 lnt ans; 23 int lim; 24 int size; 25 int root; 26 int maxsize; 27 void ade(int f,int t,int v) 28 { 29 cnt++; 30 e[cnt].twd=t; 31 e[cnt].lst=p[f].hd; 32 e[cnt].vls=v; 33 p[f].hd=cnt; 34 return ; 35 } 36 void grc_dfs(int x,int f) 37 { 38 p[x].wgt=1; 39 int maxs=-1; 40 for(int i=p[x].hd;i;i=e[i].lst) 41 { 42 int to=e[i].twd; 43 if(to==f||p[to].vis) 44 continue; 45 grc_dfs(to,x); 46 p[x].wgt+=p[to].wgt; 47 if(p[to].wgt>maxs) 48 maxs=p[to].wgt; 49 } 50 if(maxs<size-p[x].wgt) 51 maxs=size-p[x].wgt; 52 if(maxs<maxsize) 53 { 54 maxsize=maxs; 55 root=x; 56 } 57 return ; 58 } 59 void ans_dfs(int x,int fa,int dep) 60 { 61 lim=std::max(lim,dep); 62 if(has[p[x].dis]) 63 f[p[x].dis][1]++; 64 else 65 f[p[x].dis][0]++; 66 has[p[x].dis]++; 67 for(int i=p[x].hd;i;i=e[i].lst) 68 { 69 int to=e[i].twd; 70 if(to==fa||p[to].vis) 71 continue; 72 p[to].dis=p[x].dis+e[i].vls; 73 ans_dfs(to,x,dep+1); 74 } 75 has[p[x].dis]--; 76 return ; 77 } 78 void bin_dfs(int x) 79 { 80 int maxd=0; 81 p[x].vis=true; 82 g[n][0]=1; 83 for(int i=p[x].hd;i;i=e[i].lst) 84 { 85 int to=e[i].twd; 86 if(p[to].vis) 87 continue; 88 p[to].dis=n+e[i].vls; 89 lim=1; 90 ans_dfs(to,to,1); 91 maxd=std::max(maxd,lim); 92 ans+=f[n][0]*(g[n][0]-1); 93 for(int j=-lim;j<=lim;j++) 94 ans+=g[n-j][1]*f[n+j][1]+g[n-j][1]*f[n+j][0]+g[n-j][0]*f[n+j][1]; 95 for(int j=n-lim;j<=n+lim;j++) 96 { 97 g[j][0]+=f[j][0]; 98 g[j][1]+=f[j][1]; 99 f[j][0]=f[j][1]=0; 100 } 101 } 102 for(int i=n-maxd;i<=n+maxd;i++) 103 g[i][0]=g[i][1]=0; 104 for(int i=p[x].hd;i;i=e[i].lst) 105 { 106 int to=e[i].twd; 107 if(p[to].vis) 108 continue; 109 root=0; 110 size=p[to].wgt; 111 maxsize=0x3f3f3f3f; 112 grc_dfs(to,to); 113 bin_dfs(root); 114 } 115 return ; 116 } 117 int main() 118 { 119 scanf("%d",&n); 120 for(int i=1;i<n;i++) 121 { 122 int a,b,c; 123 scanf("%d%d%d",&a,&b,&c); 124 c=c*2-1; 125 ade(a,b,c); 126 ade(b,a,c); 127 } 128 root=0; 129 size=n; 130 maxsize=0x3f3f3f3f; 131 grc_dfs(1,1); 132 bin_dfs(root); 133 printf("%lld\n",ans); 134 return 0; 135 }?
轉(zhuǎn)載于:https://www.cnblogs.com/blog-Dr-J/p/10159463.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ3697: 采药人的路径(点分治)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 国家集训队 排队
- 下一篇: 快速创建springBoot