bzoj3697_FJ2014集训_采药人的路径_solution



小道士的矫情之路;
点分治,
对于每个子树,处理其内经过根(重心)的路径,然后递归下一层子树;
如何处理经过根的合法路径
合法有两个要求;
把输入的0改成-1后
1.len=0;
2.存在一个点i使被她分开的两个路径len均为零;
在每次统计中我们可以dfs统计每条从根开始的路径(half_way),
任意两条这样的路径拼成一条可能合法的路径;
check合法?
通过dfs;
统计1,每个half_way的len
还要统计,2,这个half_way上是否有一个点到half_way的终点(根之外的那个)的len=0;
一,两个half_way的len加为0才可能合法;
二,两个half_way中至少一个满足“有一个点到half_way的终点(根之外的那个)的len=0”;
只要满足一&&二,则路径合法;(自己思考why?)
1很好统计;
关键是2;
可以考虑维护一个桶;
如果root到i的路径len=x,且桶x已经有值了,则i的二合法;(自己思考why?)
由于这里细节极多,不好全部言明,故直接看代码:
 1 long long  get_ans(int root,int w){
 2     int i,j,k,l,kk,ll;
 3     long long ans=0;
 4     tot=0;if(w)map[zero]=1;
 5     dfs_ans(root,w,0);j=tot;
 6     sort(hw+1,hw+tot+1,cmp);
 7     for(i=1;i<j;i++){
 8         while(hw[i].d+hw[j].d>0&&i<j)
 9             j--;
10         if(hw[i].d+hw[j].d==0){
11             k=l=0;kk=i;ll=j;
12             if(hw[i].d==0){
13                 for(;i<=j;i++){
14                     if(hw[i].can>=2)k++;
15                     if(hw[i].can==1)l++;
16                 }
17                 ans+=(long long)(k+l)*(k+l-1)/2;
18                 ans+=(long long)k*(ll-kk+1-l-k);
19                 break;
20             }
21             while(1){
22                 if(hw[i].can)k++;i++;
23                 if(hw[i].d!=hw[i-1].d)break; 
24             }
25             while(1){
26                 if(hw[j].can)l++;j--;
27                 if(hw[j].d!=hw[j+1].d)break;
28             }
29             ans+=(long long)k*(ll-j-l)+l*(i-kk-k)+k*l;i--;
30         }
31     }
32     if(w)map[zero]=0;
33     return ans;
34 }
35 void dfs_ans(int now,int sum,int fa){
36     hw[++tot].d=sum;
37     hw[tot].can=map[zero+sum];
38     map[zero+sum]++;
39     for(int i=first[now];i;i=e[i].next)
40         if(e[i].to!=fa&&!vis[e[i].to])
41             dfs_ans(e[i].to,sum+e[i].d,now);
42     map[zero+sum]--;
43 }
View Code

由于这个操作是单次O(logn)的,于是我的做法比标解多了一个不大log;

(标解O(nlogn),本人O(nlog²n),......大约是这样)

之前桶没清干净,拍了好久没发现;

总代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int zero=100004;
  5 int n,tot;
  6 long long ans;
  7 struct half_way{
  8     int d,can;
  9 }hw[200010];
 10 int map[200010],vis[100010],size[100010],lsize[100010];
 11 struct ss{
 12     int to,next,d;
 13 }e[200010];
 14 int first[100010],num;
 15 bool cmp(half_way a,half_way b){
 16     return a.d<b.d;
 17 }
 18 void build(int ,int ,int );
 19 void part_dfs(int );
 20 void dfs_size(int ,int );
 21 int  dfs_root(int ,int ,int );
 22 long long  get_ans(int ,int );
 23 void dfs_ans(int ,int ,int );
 24 int main()
 25 {
 26     int i,j,k,l;
 27     scanf("%d",&n);
 28     for(i=1;i<n;i++){
 29         scanf("%d%d%d",&j,&k,&l);
 30         l=l?1:-1;
 31         build(j,k,l);
 32         build(k,j,l);
 33     }
 34     part_dfs(1);
 35     printf("%lld",ans);
 36     return 0;
 37 }
 38 void build(int f,int t,int wi){
 39     e[++num].next=first[f];
 40     e[num].to=t;e[num].d=wi;
 41     first[f]=num;
 42 }
 43 void part_dfs(int now){
 44     int i,root;
 45     dfs_size(now,0);
 46     root=dfs_root(now,0,now);
 47     ans+=get_ans(root,0);
 48     vis[root]=1;
 49     for(i=first[root];i;i=e[i].next)
 50         if(!vis[e[i].to]){
 51             ans-=get_ans(e[i].to,e[i].d);
 52             part_dfs(e[i].to);
 53         }
 54 }
 55 void dfs_size(int now,int fa){
 56     size[now]=1;
 57     for(int i=first[now];i;i=e[i].next)
 58         if(!vis[e[i].to]&&e[i].to!=fa){
 59             dfs_size(e[i].to,now);
 60             size[now]+=size[e[i].to];
 61         }
 62 }
 63 int dfs_root(int now,int fa,int r){
 64     int i,root=-1,wroot;
 65     lsize[now]=size[r]-size[now];
 66     for(i=first[now];i;i=e[i].next)
 67         if(!vis[e[i].to]&&e[i].to!=fa){
 68             if(size[e[i].to]>lsize[now])
 69                 lsize[now]=size[e[i].to];
 70             wroot=dfs_root(e[i].to,now,r);
 71             if(lsize[wroot]<lsize[root]||root==-1)
 72                 root=wroot;
 73         }
 74     if(lsize[now]<lsize[root]||root==-1)
 75         root=now;
 76     return root;
 77 }
 78 long long  get_ans(int root,int w){
 79     int i,j,k,l,kk,ll;
 80     long long ans=0;
 81     tot=0;if(w)map[zero]=1;
 82     dfs_ans(root,w,0);j=tot;
 83     sort(hw+1,hw+tot+1,cmp);
 84     for(i=1;i<j;i++){
 85         while(hw[i].d+hw[j].d>0&&i<j)
 86             j--;
 87         if(hw[i].d+hw[j].d==0){
 88             k=l=0;kk=i;ll=j;
 89             if(hw[i].d==0){
 90                 for(;i<=j;i++){
 91                     if(hw[i].can>=2)k++;
 92                     if(hw[i].can==1)l++;
 93                 }
 94                 ans+=(long long)(k+l)*(k+l-1)/2;
 95                 ans+=(long long)k*(ll-kk+1-l-k);
 96                 break;
 97             }
 98             while(1){
 99                 if(hw[i].can)k++;i++;
100                 if(hw[i].d!=hw[i-1].d)break; 
101             }
102             while(1){
103                 if(hw[j].can)l++;j--;
104                 if(hw[j].d!=hw[j+1].d)break;
105             }
106             ans+=(long long)k*(ll-j-l)+l*(i-kk-k)+k*l;i--;
107         }
108     }
109     if(w)map[zero]=0;
110     return ans;
111 }
112 void dfs_ans(int now,int sum,int fa){
113     hw[++tot].d=sum;
114     hw[tot].can=map[zero+sum];
115     map[zero+sum]++;
116     for(int i=first[now];i;i=e[i].next)
117         if(e[i].to!=fa&&!vis[e[i].to])
118             dfs_ans(e[i].to,sum+e[i].d,now);
119     map[zero+sum]--;
120 }

从时间复杂度和代码量上都不如标解,唉,也难怪;

原文地址:https://www.cnblogs.com/nietzsche-oier/p/6770122.html