BZOJ3697: 采药人的路径(点分治)
生活随笔
收集整理的這篇文章主要介紹了
BZOJ3697: 采药人的路径(点分治)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
采藥人的藥田是一個樹狀結構,每條路徑上都種植著同種藥材。
采藥人以自己對藥材獨到的見解,對每種藥材進行了分類。大致分為兩類,一種是陰性的,一種是陽性的。
采藥人每天都要進行采藥活動。他選擇的路徑是很有講究的,他認為陰陽平衡是很重要的,所以他走的一定是兩種藥材數目相等的路徑。采藥工作是很辛苦的,所以他希望他選出的路徑中有一個可以作為休息站的節點(不包括起點和終點),滿足起點到休息站和休息站到終點的路徑也是陰陽平衡的。他想知道他一共可以選擇多少種不同的路徑。
Input
第1行包含一個整數N。
接下來N-1行,每行包含三個整數a_i、b_i和t_i,表示這條路上藥材的類型。
Output
輸出符合采藥人要求的路徑數目。
Sample Input
71 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1解題思路:
點分治要求在尋找到一條鏈時統計答案與重心在鏈的哪個位置無關。而顯然這道題如果枚舉重心為中轉站是錯誤的,因為一條鏈只被統計一次,而中心位置很可能是錯誤的,所以我們需要修正這一點,就是統計重心路徑上可能出現的中心位置。
換句話說,開四個桶來記錄,分別記錄當前子樹內可能出現的中轉站(出現過的距離重復,在差分的意義下說明出現和為0的區間),另外一個就是之前子樹的答案,每次更新完合并桶就好了。
代碼:
?
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 }?
轉載于:https://www.cnblogs.com/blog-Dr-J/p/10159463.html
總結
以上是生活随笔為你收集整理的BZOJ3697: 采药人的路径(点分治)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国家集训队 排队
- 下一篇: 快速创建springBoot