3697: 采药人的路径
点分治模板题。
我们可以开一个桶来维护阴阳的差,如果没有休息站的限制,可以很容易的求出。那么如果有休息站的限制怎么办呢?
我们可以发现,一条合法的经过当前根的路径,休息站在起点或终点到根的路径上某一个点,那么我们是不是可以预处理出哪个点到根的路径上可以有休息站,哪个不可以呢,有休息站的意思就是从该点到根有一段阴阳平衡的路径,这个可以通过dfs一遍判断根到某个点的路径上是否存在和这个点阴阳差一样的点来得到。
但是实现的时候有一些细节问题,如果某个点到根路径上休息站恰好只能选在根,那么这时根是不能作为终点出现的,这种情况需要特殊判断掉,于是我的第二维开了3的大小,分别表示没有休息站,有一个,有多个。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int inf=1e5+10; 5 int n,tot,fi[inf],to[inf<<1],cost[inf<<1],nxt[inf<<1]; 6 void link(int x,int y,int z){ 7 to[++tot]=y;nxt[tot]=fi[x];fi[x]=tot;cost[tot]=z; 8 } 9 int vis[inf],siz[inf]; 10 int id,Min_size; 11 void getsize(int x,int f){ 12 siz[x]=1; 13 for(int i=fi[x];i;i=nxt[i]){ 14 if(vis[to[i]] || to[i]==f)continue; 15 getsize(to[i],x); 16 siz[x]+=siz[to[i]]; 17 } 18 } 19 void getrt(int x,int f,int y){ 20 int tmp=-0x3fffffff; 21 for(int i=fi[x];i;i=nxt[i]){ 22 if(vis[to[i]] || to[i]==f)continue; 23 getrt(to[i],x,y); 24 tmp=max(tmp,siz[to[i]]); 25 } 26 tmp=max(tmp,y-siz[x]); 27 if(tmp<Min_size){ 28 Min_size=tmp; 29 id=x; 30 } 31 } 32 LL ans; 33 int h[inf<<1][3]; 34 int sta[inf][2],top,clea[inf][2],r; 35 int cnt[inf<<1],dep[inf]; 36 void dfs1(int x,int f,int now){ 37 dep[x]=now; 38 for(int i=fi[x];i;i=nxt[i]){ 39 if(vis[to[i]] || to[i]==f)continue; 40 dfs1(to[i],x,now+cost[i]); 41 } 42 } 43 void dfs2(int x,int f,int now){ 44 if(cnt[now])ans+=h[inf*2-now][0]+h[inf*2-now][1]+h[inf*2-now][2]; 45 else ans+=h[inf*2-now][1]+h[inf*2-now][2]; 46 if(cnt[now]==1 && now==inf)ans--; 47 if(cnt[now]>=2){ 48 sta[++top][0]=now;sta[top][1]=2; 49 } 50 else sta[++top][0]=now,sta[top][1]=cnt[now]; 51 cnt[now]++; 52 for(int i=fi[x];i;i=nxt[i]){ 53 if(vis[to[i]] || to[i]==f)continue; 54 dfs2(to[i],x,now+cost[i]); 55 } 56 cnt[now]--; 57 } 58 void getans(int x){ 59 r=0; 60 h[inf][0]=1; 61 cnt[inf]=1; 62 for(int i=fi[x];i;i=nxt[i]){ 63 if(vis[to[i]])continue; 64 top=0; 65 dfs1(to[i],x,cost[i]+inf); 66 dfs2(to[i],x,cost[i]+inf); 67 for(int j=1;j<=top;j++){ 68 h[sta[j][0]][sta[j][1]]++; 69 clea[++r][0]=sta[j][0]; 70 clea[r][1]=sta[j][1]; 71 } 72 } 73 for(int i=1;i<=r;i++)h[clea[i][0]][clea[i][1]]=0; 74 } 75 void work(int x){ 76 getsize(x,0); 77 Min_size=0x3fffffff; 78 getrt(x,0,siz[x]); 79 int rt=id; 80 vis[rt]=1; 81 getans(rt); 82 for(int i=fi[rt];i;i=nxt[i]){ 83 if(vis[to[i]])continue; 84 work(to[i]); 85 } 86 } 87 int main() 88 { 89 scanf("%d",&n); 90 for(int i=1;i<n;i++){ 91 int x,y,z; 92 scanf("%d%d%d",&x,&y,&z); 93 if(!z)z--; 94 link(x,y,z);link(y,x,z); 95 } 96 work(1); 97 printf("%lld\n",ans); 98 return 0; 99 }