zoukankan      html  css  js  c++  java
  • 解题:CF1118F2 Tree Cutting (Hard Version)

    题面

    好题不问Div(这是Div3最后一题,不得不说Mike真是强=。=)

    首先同一个颜色的点的LCA要和它们在一个划分出的块里,那么我们先按颜色把所有点到它们的LCA的路径涂色,如果这个过程中出现了重合的颜色则说明无解。

    之后问题转化为一个树形DP问题,设$dp[i][0/1]$表示以$i$为根的子树中i是否划入一个有颜色的块的方案数。然后讨论转移:

    1.如果i自身没有颜色

    ①如果i不划入有颜色的块,那么直接继承子树信息,乘法原理统计,$dp[i][0]=prod_{v∈son_i}(dp[v][0]+dp[v][1])$

    ②如果i划入有颜色的块,那么对于每一个子树都单独统计一遍划入其中的方案数,$dp[i][1]=sum_{v∈son_i}dp[v][1]prod_{w∈son_i&&w!=v}(dp[w][0]+dp[w][1])$,维护每个节点子节点的前缀后缀乘积来转移

    2.如果i自身有颜色

    ①如果i不划入有颜色的块,那么......不划入有颜色的块=。=???$dp[i][0]=0$

    ②如果i划入有颜色的块,同理于1.①

    (因为一个睿智错误多调了一个小时

      1 #include<cstdio>
      2 #include<vector>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define vint vector<int>
      6 #define vit vector<int>::iterator
      7 using namespace std;
      8 const int N=300005,mod=998244353;
      9 int p[N],noww[2*N],goal[2*N],siz[N];
     10 int anc[N],dep[N],imp[N],top[N],col[N],dp[N][2]; 
     11 int n,k,cnt,t1,t2; vint ve[N];
     12 void Link(int f,int t)
     13 {
     14     noww[++cnt]=p[f];
     15     goal[cnt]=t,p[f]=cnt;
     16     noww[++cnt]=p[t];
     17     goal[cnt]=f,p[t]=cnt;
     18 }
     19 void Add(int &x,int y)
     20 {
     21     x+=y;
     22     if(x>=mod) x-=mod;
     23 }
     24 void Mul(int &x,int y)
     25 {
     26     x=1ll*x*y%mod;
     27 }
     28 void DFS(int nde,int fth,int dth)
     29 {
     30     int tmp=0;
     31     siz[nde]=1,anc[nde]=fth,dep[nde]=dth;
     32     for(int i=p[nde];i;i=noww[i])
     33         if(goal[i]!=fth)
     34         {
     35             DFS(goal[i],nde,dth+1);
     36             siz[nde]+=siz[goal[i]];
     37             if(siz[goal[i]]>tmp)
     38                 tmp=siz[goal[i]],imp[nde]=goal[i];
     39         }
     40 }
     41 void Decompose(int nde,int tpp)
     42 {
     43     top[nde]=tpp;
     44     if(imp[nde])
     45     {
     46         Decompose(imp[nde],tpp);
     47         for(int i=p[nde];i;i=noww[i])
     48             if(goal[i]!=anc[nde]&&goal[i]!=imp[nde])
     49                 Decompose(goal[i],goal[i]);
     50     }
     51 }
     52 int LCA(int x,int y)
     53 {
     54     while(top[x]!=top[y])
     55     {
     56         if(dep[top[x]]<dep[top[y]])
     57             swap(x,y); x=anc[top[x]];
     58     }
     59     return dep[x]<dep[y]?x:y;
     60 }
     61 void Climb(int nde,int lca,int cor)
     62 {
     63     while(nde!=lca)
     64     {
     65         nde=anc[nde];
     66         if(col[nde])
     67         {
     68             if(col[nde]==cor) return;
     69             else printf("0"),exit(0);
     70         }
     71         col[nde]=cor;
     72     }
     73 }
     74 void Getans(int nde,int fth)
     75 {
     76     vint v1,v2; 
     77     dp[nde][(bool)col[nde]]=1;
     78     for(int i=p[nde];i;i=noww[i])
     79         if(goal[i]!=fth)
     80         {
     81             int g=goal[i]; Getans(g,nde);
     82             int s=(dp[g][0]+dp[g][1])%mod;
     83             v1.push_back(s),v2.push_back(s);
     84             col[nde]?Mul(dp[nde][1],s):Mul(dp[nde][0],s);
     85         }
     86     if(!col[nde]&&v1.size())
     87     {
     88         int sz=v1.size(),pt=0;
     89         for(int i=1;i<sz;i++) Mul(v1[i],v1[i-1]);
     90         for(int i=sz-2;i>=0;i--) Mul(v2[i],v2[i+1]);
     91         for(int i=p[nde];i;i=noww[i])
     92             if(goal[i]!=fth)
     93             {
     94                 int pre=pt?v1[pt-1]:1,suf=(pt==sz-1)?1:v2[pt+1];
     95                 int tmp=dp[goal[i]][1]; 
     96                 Mul(tmp,pre),Mul(tmp,suf),Add(dp[nde][1],tmp),pt++;
     97             }
     98     }
     99 }
    100 int main ()
    101 {
    102     scanf("%d%d",&n,&k);
    103     for(int i=1;i<=n;i++)
    104     {
    105         scanf("%d",&col[i]);
    106         if(col[i]) ve[col[i]].push_back(i);
    107     }
    108     for(int i=1;i<n;i++)
    109         scanf("%d%d",&t1,&t2),Link(t1,t2);
    110     DFS(1,0,1),Decompose(1,1);
    111     for(int i=1;i<=k;i++)
    112     {
    113         vint v=ve[i]; int lca=*v.begin();
    114         if(v.size()>1) 
    115         {
    116             vit it=++v.begin();
    117             while(it!=v.end())
    118                 lca=LCA(lca,*it++);
    119         }
    120         vit it=v.begin();
    121         while(it!=v.end())
    122             Climb(*it++,lca,i);
    123     }
    124     Getans(1,0);
    125 //    for(int i=1;i<=n;i++) 
    126 //        printf("%d %d %d
    ",mar[i],dp[i][0],dp[i][1]);    
    127     printf("%d",dp[1][1]);
    128     return 0;
    129 }
    View Code
  • 相关阅读:
    用Python完成一个汇率转换器
    鸿蒙如何用JS开发智能手表App
    鸿蒙如何用JS开发智能手表App
    SAP Spartacus SplitViewComponent Migration 的一个具体例子
    SAP Spartacus B2B 页面 Popover Component 的条件显示逻辑
    SAP Spartacus 升级时关于 schematics 的更新
    SAP Spartacus B2B 页面 Disable 按钮的显示原理
    SAP Spartacus B2B 页面 Disable Confirmation 对话框的显示原理
    通过 Feature Level 动态控制 SAP Spartacus 的页面显示
    SAP Commerce Cloud Build Manifest Components
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/10430135.html
Copyright © 2011-2022 走看看