• BZOJ 3697/3127 采药人的路径 (点分治)


    题目大意:

    从前有一棵无向树,树上边权均为$0$或$1$,有一个采药人,他认为如果一条路径上边权为$0$和$1$的边数量相等,那么这条路径阴阳平衡。他想寻找一条合法的采药路径,保证阴阳平衡。然后他发现采药很累,于是乎他需要保证这条路径上有一个中转站,路径两个端点到中转站的路径都需要阴阳平衡 $n leqslant 10^{5}$,求合法路径数

    把$0$边边权变成$-1$,易发现如果一条路径阴阳平衡,那么边权总和为$0$

    由于是树上路径的计数问题,考虑树分治,每次选中心作为根,设某点$x$到根的路径的边权和为$dis_{x}$

    把中转站加进去会发生什么呢?

    如果某个点$x$到根的路径上能设置中转站,那么根到$x$的路径上一定存在一点$y$,$dis_{y}=dis_{x}$,即$x$到$y$的路径$dis$为$0$,这个操作可以用桶实现

    现在要在根统计答案了,显然每个点分为种情况,到根的路径能设置中转站和不能,用桶分别计数即可,设为$f[i][0]$和$f[i][1]$,表示$dis=i$时的方案数

    发现还有$dis<0$的情况,需要额外记录一个数组$g$

    那么答案就是$sum_{i=1} f[i][0]*g[i][1]+f[i][1]*g[i][0]+f[i][1]*g[i][1]$

    还要去掉不合法的情况,在当前根的每个子节点依然进行上述方法计数即可

    $dis=0$的情况需要单独讨论,所有$dis=0$的路径都能两两匹配。此外,不以根节点为中转站,且$dis=0$的路径也一定合法

    细节比较多

      1 #include <cmath>
      2 #include <vector>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #define N1 100010
      7 #define M1 (N1<<1)
      8 #define ll long long
      9 #define inf 233333333
     10 using namespace std;
     11 
     12 int gint()
     13 {
     14     int ret=0,fh=1;char c=getchar();
     15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     17     return ret*fh;
     18 }
     19 int n;
     20 
     21 struct Edge{
     22 int to[M1],nxt[M1],val[M1],head[N1],cte;
     23 void ae(int u,int v,int w)
     24 {cte++;to[cte]=v,nxt[cte]=head[u],val[cte]=w,head[u]=cte;}
     25 }E;
     26 
     27 int use[N1],mi,G,S,tsz,ma;
     28 int sf[N1],sg[N1],ms[N1],sz[N1],dis[N1];
     29 int f[N1][2],g[N1][2]; ll ans; int que[N1],tl;
     30 //int dep[N1],fa[N1],de;
     31 void dfs_sum(int u,int dad)
     32 {
     33     que[++tl]=u;
     34     if(dis[u]>=0){
     35         if(sf[dis[u]]) f[dis[u]][1]++;
     36         else f[dis[u]][0]++;
     37         sf[dis[u]]++;  ma=max(ma,dis[u]);
     38         if(u==S) sf[0]--,f[0][0]--;
     39     }else{
     40         if(sg[-dis[u]]) g[-dis[u]][1]++;
     41         else g[-dis[u]][0]++;
     42         sg[-dis[u]]++; ma=max(ma,-dis[u]);
     43     }
     44     for(int j=E.head[u];j;j=E.nxt[j])
     45     {
     46         if(E.to[j]==dad||use[E.to[j]]) continue;
     47         dis[E.to[j]]=dis[u]+E.val[j];
     48         dfs_sum(E.to[j],u);
     49     }
     50     if(dis[u]>=0) sf[dis[u]]--; 
     51     else sg[-dis[u]]--;
     52 }
     53 void gra(int u,int dad)
     54 {
     55     sz[u]=1; ms[u]=0;
     56     for(int j=E.head[u];j;j=E.nxt[j])
     57     {   
     58         int v=E.to[j]; 
     59         if(v==dad||use[v]) continue;
     60         gra(v,u); sz[u]+=sz[v];
     61         ms[u]=max(ms[u],sz[v]);
     62     }
     63     ms[u]=max(ms[u],tsz-sz[u]);
     64     if(ms[u]<ms[G]) G=u;
     65 }
     66 void clr()
     67 {
     68     int x;
     69     while(tl)
     70     {
     71         x=que[tl]; tl--;
     72         if(dis[x]>=0) f[dis[x]][0]=f[dis[x]][1]=0;
     73         else g[-dis[x]][0]=g[-dis[x]][1]=0;
     74     }
     75     sg[0]=sf[0]=0;
     76 }
     77 void calc(int u,int type)
     78 {
     79     ma=0; dfs_sum(u,-1);
     80     ans+=( 1ll*f[0][0]*(f[0][0]-1)/2 + 1ll*f[0][1]*(f[0][1]-1)/2 + 1ll*f[0][0]*f[0][1] )*type;
     81     for(int i=1;i<=ma;i++)
     82         ans+=( 1ll*f[i][0]*g[i][1] + 1ll*f[i][1]*g[i][0] + 1ll*f[i][1]*g[i][1])*type;
     83     if(type==1) ans+=f[0][1];
     84     clr();
     85 }
     86 void main_dfs(int u)
     87 {
     88     int j,v; use[u]=1; S=u; dis[u]=0; calc(u,1); 
     89     for(j=E.head[u];j;j=E.nxt[j])
     90     {
     91         v=E.to[j]; if(use[v]) continue;
     92         G=0; tsz=sz[v]; gra(v,u);
     93         calc(v,-1);
     94         main_dfs(G);
     95     }
     96 }
     97 
     98 int main()
     99 {
    100     //freopen("t2.in","r",stdin);
    101     int i,x,y,z;
    102     scanf("%d",&n);
    103     for(i=1;i<n;i++)
    104     {
    105         x=gint(),y=gint(),z=gint();
    106         z=((z)?1:-1);
    107         E.ae(x,y,z),E.ae(y,x,z);
    108     }
    109     ms[0]=tsz=n; G=0; gra(1,-1); gra(G,-1);
    110     main_dfs(G);
    111     printf("%lld
    ",ans);
    112     return 0;
    113 }
  • 相关阅读:
    如何使用参数给 Scrapy 爬虫增加属性
    如何正确在 PyCharm 中调试 Scrapy 爬虫?
    Chrome 开发者工具的最佳用法
    Chrome 开发者工具的各种骚技巧
    跨库数据备份还原、迁移工具
    意向锁
    十六进制

    lombok @Builder注解
    什么是强引用、软引用、弱引用、虚引用?
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10184506.html
Copyright © 2020-2023  润新知