zoukankan      html  css  js  c++  java
  • 「FJ2014集训」采药人的路径 [点分治]

    题意

      一棵边权为-1或1的树,求满足条件的路径数:路径边权和为0,存在路径上异于端点的一点到端点的边权和为0。


    考虑点分治,设路径端点为$u,v$,中间满足条件的点为$k$,则$dis[u]+dis[v]=0$ 且 $dis[u]=dis[k]$或$dis[v]=dis[k]$。

    搜距离的时候将一棵子树中的距离按照是否有相等的前缀距离分成两组,记为$f[i][0],f[i][1]$,与前面几颗子树的和$g[i][0],g[i][1]$

    计算这一颗子树与之前子树的路径数 $ans+=f[i][0]*g[-i][1]+f[i][1]*g[-i][0]+f[i][1]*g[-i][1]$

    计算子树内到分治中心的路径数 $ans+=f[0][1]$

    距离枚举范围用深度进行限制,记录$maxdepth$

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N=100010;
     6 const int inf=0x3f3f3f3f;
     7 typedef long long ll;
     8 int n,rt,S,mf[N],size[N],x,y,z,dis[N],d[N],st[N<<1],f[N<<1][2],g[N<<1][2],md;
     9 bool vis[N],use[N<<1];
    10 int p,head[N],to[N<<1],nxt[N<<1],w[N<<1];
    11 ll ans;
    12 inline int read() {
    13     int re=0; char ch=getchar();
    14     while (ch<'0'||ch>'9') ch=getchar();
    15     while (ch>='0'&&ch<='9') re=re*10+ch-48,ch=getchar();
    16     return re;
    17 }
    18 inline void add(int x,int y,int z) {
    19     to[++p]=y; nxt[p]=head[x]; w[p]=z; head[x]=p;
    20     to[++p]=x; nxt[p]=head[y]; w[p]=z; head[y]=p;
    21 }
    22 void get_rt(int x,int fa) {
    23     size[x]=1; mf[x]=0;
    24     for (int i=head[x]; i; i=nxt[i]) {
    25         if (to[i]==fa || vis[to[i]]) continue;
    26         get_rt(to[i],x);
    27         size[x]+=size[to[i]];
    28         if (size[to[i]]>mf[x]) mf[x]=size[to[i]];
    29     }
    30     mf[x]=max(mf[x],S-size[x]);
    31     if (mf[x]<mf[rt]) rt=x;
    32 }
    33 void get_dis(int x,int fa,int dep) {
    34     dis[++dis[0]]=d[x]; md=max(md,dep);
    35     if (st[d[x]]) f[d[x]][1]++; else f[d[x]][0]++;
    36     st[d[x]]++;
    37     for (int i=head[x]; i; i=nxt[i]) {
    38         if (to[i]==fa || vis[to[i]]) continue;
    39         d[to[i]]=d[x]+w[i];
    40         get_dis(to[i],x,dep+1);
    41     }
    42     st[d[x]]--;
    43 }
    44 void dfs(int x) {
    45     vis[x]=1; int maxd=0;
    46     for (int i=head[x]; i; i=nxt[i]) {
    47         if (vis[to[i]]) continue;
    48         dis[0]=0; d[to[i]]=n+w[i];
    49         md=0; get_dis(to[i],x,1); maxd=max(maxd,md);
    50         f[n][0]+=f[n][1]; ans+=f[n][1]; f[n][1]=0;
    51         ans+=1ll*f[n][0]*g[n][0]; g[n][0]+=f[n][0],f[n][0]=0;
    52         for (int i=n+md; i>n; i--) {
    53             ans+=1ll*f[i][0]*g[(n<<1)-i][1]+1ll*f[i][1]*g[(n<<1)-i][0]
    54                 +1ll*f[i][1]*g[(n<<1)-i][1];
    55             ans+=1ll*g[i][0]*f[(n<<1)-i][1]+1ll*g[i][1]*f[(n<<1)-i][0]
    56                 +1ll*g[i][1]*f[(n<<1)-i][1];
    57             g[i][0]+=f[i][0]; g[i][1]+=f[i][1];
    58             g[(n<<1)-i][0]+=f[(n<<1)-i][0]; g[(n<<1)-i][1]+=f[(n<<1)-i][1];
    59             f[i][0]=f[i][1]=f[(n<<1)-i][0]=f[(n<<1)-i][1]=0;
    60         }
    61     }
    62     g[n][0]=0;
    63     for (int i=n+maxd; i>n; i--) g[i][0]=g[i][1]=g[(n<<1)-i][0]=g[(n<<1)-i][1]=0;
    64     for (int i=head[x]; i; i=nxt[i]) {
    65         if (vis[to[i]]) continue;
    66         S=size[to[i]]; mf[rt=0]=inf;
    67         get_rt(to[i],x); dfs(rt);
    68     }
    69 }
    70 int main() {
    71     n=read();
    72     for (int i=1; i<n; i++) x=read(),y=read(),z=read() ? 1:-1,add(x,y,z);
    73     S=n; mf[rt=0]=inf;
    74     get_rt(1,0); dfs(rt);
    75     printf("%lld\n",ans);
    76     return 0;
    77 }
  • 相关阅读:
    交换机模拟器
    bootstrap-分页-默认分页
    bootstrap-分页-默认分页
    bootstrap-分页-默认分页
    交易系统查询带上for update
    集成开发环境(IDE) Mix介绍
    Dapp及相关开发工具介绍
    区块链技术视频网站EthCast.com上线
    区块链:最小可行区块链原理解析1
    账户、交易核心概念及投注合约解析
  • 原文地址:https://www.cnblogs.com/hnooo/p/10145800.html
Copyright © 2011-2022 走看看