bzoj3697: 采药人的路径

Posted hyghb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3697: 采药人的路径相关的知识,希望对你有一定的参考价值。

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 }
View Code

 

以上是关于bzoj3697: 采药人的路径的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3697采药人的路径

BZOJ3697: 采药人的路径

bzoj3697采药人的路径 树的点分治

3697. 采药人的路径点分治

BZOJ 3697

bzoj3127/3697 [Usaco2013 Open]Yin and Yang