[PKUSC2019] [tree line tree staining merger] [DP] tree

Description

Gives a tree of n points, there are m colors, dyeing to give each node, the neighboring node is not the same color.
In addition there are k limitations of the form x y color dot is not
possible to limit a plurality of the same node yo.
Evaluating the number of 998,244,353 modulo results.

Solution

The examination room have been thinking about how to make inclusion and exclusion, how Dunong out.
Learn silly.

Consider violence DP
disposed \ (F [i] [j] \) for the current i is processed in the subtree rooted, i is the color number of program j.
Note \ (g [i] = \ sum \ limits_ {k} f [i] [k] \)

Obviously metastasis \ [f [i] [j ] = [! Ban [i] [j]] \ prod_ {p \ in son [i]} (g [p] -f [p] [j]) \]

But such is the number of states \ (n * m \) , we found that only need to remember the tree erupted in some color, other colors of the answer is the same.
In this way the number of states cut to \ (the n-* k \) , but is still very large, so we consider the tree line to maintain.

When we transferred the subtree combined one to the root
about \ (f [i] [j
] = (g [p] -f [p] [j]) * f [i] [j] \) in accordance with this we can merge the tree line.
If only the father has, directly take the
son of the father has consolidated violence
only son put any brackets apart, is multiplied by \ (- f [i] [ j] \) plus \ (g [p] * f [ i] [j] \)
require maintenance interval by interval plus, a similar function can be maintained.
The time complexity is about \ (O ((n-K +) \ log m) \) , specifically look at the code.

Code

I wrote to beat no problem, leaving it as it is

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(inti i=a;i>=b;--i)
#define N 200005
#define M 13000005
#define LL long long
#define mo 998244353
using namespace std;
int n,m,l,fs[N],nt[2*N],dt[2*N],m1;
vector<int> qs[N];
LL ksm(LL k,LL n)
{
    LL s=1;
    for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
    return s;
}
int n1,t[M][2],sz[M],rt[N];
LL sp[M],g[N],f[N],lz[M][2];
void nwp(int &k)
{
    if(!k) k=++n1,lz[k][0]=1,lz[k][1]=0;
}
void ins(int k,int l,int r,int x,int v)
{
    if(l==r) {sp[k]=0,sz[k]=1;return;}
    int mid=(l+r)>>1;
    if(x<=mid) nwp(t[k][0]),ins(t[k][0],l,mid,x,v);
    else nwp(t[k][1]),ins(t[k][1],mid+1,r,x,v);
    sp[k]=(sp[t[k][0]]+sp[t[k][1]]);
    if(sp[k]>=mo) sp[k]-=mo;
    sz[k]=sz[t[k][0]]+sz[t[k][1]];
}
LL gp,fp,fk,vs;
void upd(int k,LL u,LL v)
{
    sp[k]=(u*sp[k]+v*sz[k])%mo;
    lz[k][0]=lz[k][0]*u%mo;
    lz[k][1]=(lz[k][1]*u%mo+v)%mo;
}
void down(int k)
{
    if(lz[k][0]!=1||lz[k][1]!=0)
    {
        if(t[k][0]) upd(t[k][0],lz[k][0],lz[k][1]);
        if(t[k][1]) upd(t[k][1],lz[k][0],lz[k][1]);
        lz[k][0]=1,lz[k][1]=0;  
    }   
}
void mrg(int &k,int x,int l,int r)
{
    if(!k)
    {
        if(!x) return;
        k=x,upd(k,mo-fk,gp*fk%mo);
        return;
    }
    if(!x) {upd(k,(gp-fp+mo)%mo,0);return;}
    if(l==r) {sp[k]=(gp-sp[x]+mo)%mo*sp[k]%mo,sz[k]=sz[k]|sz[x];return;}
    int mid=(l+r)>>1;
    down(k),down(x);
    mrg(t[k][0],t[x][0],l,mid);
    mrg(t[k][1],t[x][1],mid+1,r);
    sp[k]=(sp[t[k][0]]+sp[t[k][1]])%mo;
    sz[k]=sz[t[k][0]]+sz[t[k][1]];
}
void dfs(int k,int fa)
{
    f[k]=1;
    nwp(rt[k]);
    int r=qs[k].size();
    fo(j,0,r-1) ins(rt[k],1,m,qs[k][j],0);
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p!=fa) 
        {
            dfs(p,k);
            gp=g[p],fk=f[k],fp=f[p];
            mrg(rt[k],rt[p],1,m);
            f[k]=(g[p]-f[p]+mo)%mo*f[k]%mo;
        }
    }
    g[k]=(f[k]*(LL)(m-sz[rt[k]])%mo+sp[rt[k]])%mo;
}
void link(int x,int y)
{
    nt[++m1]=fs[x];
    dt[fs[x]=m1]=y;
}
int main()
{
    cin>>n>>m>>l;
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y),link(y,x);        
    }
    fo(i,1,l)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        qs[x].push_back(y);
    }
    dfs(1,0);
    printf("%lld\n",g[1]);
}

Guess you like

Origin www.cnblogs.com/BAJimH/p/10942994.html