BZOJ3697: 采药人的路径

Posted

tags:

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

传送门

不是那么裸的点分治。

 

$f[i][0/1]$表示当前节点的一个子树中总权值和为$i$,且是否存在一个前缀使得其前缀和为$i$

$g[i][0/1]$表示当前节点的已遍历过的子树,其余一样。

 

对于每个节点

 $ans_{node}=g[0][0]∗f[0][0]+ \sum (g[−i][0]∗f[i][1]+g[−i][1]∗f[i][0]+g[−i][1]∗f[i][1])$

另外,Race那道题选根的方案在这里好像不是很适用,容易出问题,还是换黄学长的比较好。

技术分享
  1 //BZOJ 3697
  2 //by Cydiater
  3 //2016.9.26
  4 #include <iostream>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <string>
  8 #include <algorithm>
  9 #include <queue>
 10 #include <map>
 11 #include <ctime>
 12 #include <cmath>
 13 #include <iomanip>
 14 #include <cstdlib>
 15 using namespace std;
 16 #define ll long long
 17 #define up(i,j,n)       for(int i=j;i<=n;i++)
 18 #define down(i,j,n)     for(int i=j;i>=n;i--)
 19 const int MAXN=1e6+5;
 20 const int oo=0x3f3f3f3f;
 21 inline int read(){
 22     char ch=getchar();int x=0,f=1;
 23     while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();}
 24     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
 25     return x*f;
 26 }
 27 int N,LINK[MAXN],len=0,sum,root,siz[MAXN],dis[MAXN],pre[MAXN],deep[MAXN];
 28 int maxdeep,max_siz[MAXN];
 29 ll ans=0,f[MAXN][2],g[MAXN][2];
 30 bool vis[MAXN];
 31 struct edge{
 32     int y,next,v;
 33 }e[MAXN];
 34 namespace solution{
 35     inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
 36     void init(){
 37         N=read();
 38         up(i,2,N){
 39             ll x=read(),y=read(),v=read()==0?-1:1;
 40             insert(x,y,v);
 41             insert(y,x,v);
 42         }
 43     }
 44     void make_root(int node,int fa){
 45         max_siz[node]=0;siz[node]=1;
 46         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 47             make_root(e[i].y,node);
 48             siz[node]+=siz[e[i].y];
 49             max_siz[node]=max(max_siz[node],siz[e[i].y]);
 50         }
 51         max_siz[node]=max(max_siz[node],sum-max_siz[node]);
 52         if(max_siz[node]<max_siz[root])root=node;
 53     }
 54     void dfs(int node,int father){
 55         if(pre[dis[node]])  f[dis[node]][1]++;
 56         else                f[dis[node]][0]++;
 57         pre[dis[node]]++;
 58         maxdeep=max(deep[node],maxdeep);
 59         for(int i=LINK[node];i;i=e[i].next)
 60             if(e[i].y!=father&&!vis[e[i].y]){
 61                 deep[e[i].y]=deep[node]+1;
 62                 dis[e[i].y]=dis[node]+e[i].v;
 63                 dfs(e[i].y,node);
 64             }
 65         pre[dis[node]]--;
 66     }
 67     void work(int node){
 68         vis[node]=1;g[N][0]=1;int mx=0;
 69         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){
 70             dis[e[i].y]=e[i].v+N;deep[e[i].y]=1;maxdeep=1;
 71             dfs(e[i].y,0);mx=max(mx,maxdeep);
 72             ans+=1LL*(g[N][0]-1)*f[N][0];
 73             up(k,-maxdeep,maxdeep)
 74                 ans+=1LL*g[N-k][0]*f[N+k][1]+1LL*g[N-k][1]*f[N+k][0]+1LL*g[N-k][1]*f[N+k][1];
 75             up(j,N-maxdeep,N+maxdeep){
 76                 g[j][0]+=f[j][0];
 77                 g[j][1]+=f[j][1];
 78                 f[j][0]=f[j][1]=0;
 79             }
 80         }
 81         up(j,N-mx,N+mx)g[j][0]=g[j][1]=0;
 82         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){
 83             root=0;sum=siz[e[i].y];
 84             make_root(e[i].y,0);
 85             work(root);
 86         }
 87     }
 88     void slove(){
 89         sum=N;root=0;max_siz[root]=N;
 90         make_root(1,0);
 91         work(root);
 92     }
 93     void output(){
 94         cout<<ans<<endl;
 95     }
 96 }
 97 int main(){
 98     //freopen("input.in","r",stdin);
 99     using namespace solution;
100     init();
101     slove();
102     output();
103     return 0;
104 }
View Code

 

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

BZOJ 3697采药人的路径

BZOJ3697: 采药人的路径

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

3697. 采药人的路径点分治

BZOJ 3697

bzoj3127/3697 [Usaco2013 Open]Yin and Yang