bzoj 3697: 采药人的路径

点分治自己水的题(以为这辈子也做不出点分治了23333)(此题坑爹,需要LL)

考虑这道题,需要求出的是01数量相同搞的路径,而且,需要有一个休息点(这个有意思)

我们来分析这个休息点,我们设一条路径满足要求,那么休息点也就从起点到休息点01相同。那么来处理休息点。

开始打标记。标记从根节点走过的一个路径和d,现在的点x,那么只需要的是在根节点到x的路径上再有一个点的距离为x即可,那么那个点就可以作为休息点。

所以,我们设t[?+N][0/1](设0的路径权值为-1,1的为1,所以?需要加个常数N)为距离根节点距离为?,1表示中间有休息点,0表示没有休息点。那么答案就是t[N-?][1/0]

如果中间有休息点,就加t[N-?][0]+t[N-?][1],如果没有,那么就只能加t[N-?][1],统计答案和bzoj2599的方法相似(下一篇会有)(貌似变成心机婊了2333)

  1 #include<bits/stdc++.h>
  2 #define N 100005
  3 #define M 10000005
  4 #define LL long long
  5 #define inf 0x3f3f3f3f
  6 using namespace std;
  7 inline int ra()
  8 {
  9     int x=0,f=1; char ch=getchar();
 10     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
 11     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
 12     return x*f;
 13 }
 14 struct node{
 15     int to,next,v;
 16 }e[N<<1];
 17 int size[N],f[N],d[N],n,head[N],cnt,sum,root;
 18 LL ans,t[N<<1][3];
 19 bool vis[N]; int inq[N<<1];
 20 void insert(int x, int y, int v)
 21 {
 22     e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].v=v; head[x]=cnt;
 23 }
 24 void getroot(int x, int fa)
 25 {
 26     size[x]=1; f[x]=0;
 27     for (int i=head[x];i;i=e[i].next)
 28     {
 29         if (vis[e[i].to] || e[i].to==fa) continue;
 30         getroot(e[i].to,x);
 31         size[x]+=size[e[i].to];
 32         f[x]=max(f[x],size[e[i].to]);
 33     }
 34     f[x]=max(f[x],sum-size[x]);
 35     if (f[x]<f[root]) root=x;
 36 }
 37 void cal(int x, int fa)
 38 {
 39     if (inq[d[x]+N]) 
 40         ans+=t[N-d[x]][1]+t[N-d[x]][0];
 41     else ans+=t[N-d[x]][1];
 42     inq[d[x]+N]++;
 43     for (int i=head[x];i;i=e[i].next)
 44     {
 45         if (e[i].to==fa || vis[e[i].to]) continue;
 46         d[e[i].to]=d[x]+e[i].v;
 47         cal(e[i].to,x);
 48     }
 49     inq[d[x]+N]--;
 50 }
 51 void add(int x, int fa, int flag)
 52 {
 53     if (flag) {
 54         if (inq[d[x]+N]) t[d[x]+N][1]++;
 55             else t[d[x]+N][0]++;
 56     }
 57     else t[d[x]+N][1]=t[d[x]+N][0]=0;
 58     inq[d[x]+N]++;
 59     for (int i=head[x];i;i=e[i].next)
 60         if (!vis[e[i].to] && fa!=e[i].to)
 61             add(e[i].to,x,flag);
 62     inq[d[x]+N]--;
 63 }
 64 void work(int x)
 65 {
 66     vis[x]=1; t[N][0]=1;
 67     for (int i=head[x];i;i=e[i].next)
 68     {
 69         if (vis[e[i].to]) continue;
 70         d[e[i].to]=e[i].v; 
 71         cal(e[i].to,0);
 72         inq[N]=1;
 73         add(e[i].to,0,1);
 74         inq[N]=0;
 75     }
 76     for (int i=head[x];i;i=e[i].next)
 77         if (!vis[e[i].to]) add(e[i].to,0,0);
 78     for (int i=head[x];i;i=e[i].next)
 79     {
 80         if (vis[e[i].to]) continue;
 81         root=0; sum=size[e[i].to];
 82         getroot(e[i].to,0);
 83         work(root);
 84     }
 85 }
 86 int main()
 87 {
 88     n=ra();
 89     for (int i=1; i<n; i++)
 90     {
 91         int x=ra(),y=ra(),v=ra();
 92         if (v==0) v=-1;
 93         insert(x,y,v); insert(y,x,v);
 94     }
 95     sum=f[0]=n;
 96     getroot(1,0);
 97     work(root);
 98     cout<<ans;
 99     return 0;
100 }

 

posted @ 2017-02-20 12:03  ws_ccd  阅读(190)  评论(0编辑  收藏  举报