[PKUSC2019] 트리 라인 트리 염색 합병 [DP] 트리

기술

N 포인트의 트리를 제공 m 색상 각 노드를 제공하는 염색이 있으며, 이웃 노드는 동일한 컬러 아니다.
또한 폼 X Y 컬러 도트 K 제한은 없다있다
동일한 노드 요 복수를 제한 할 수있다.
998,244,353 모듈 결과의 수를 평가.

해결책

시험 방, 포함 및 제외하는 방법 Dunong 밖으로 만드는 방법에 대해 생각하고있다.
바보 알아보세요.

고려 폭력 DP가
배치 \ (F가 [I] [J] \) 전류 (I)를 루트로하는 서브 트리에서 처리를 위해, 전 프로그램 J 색 번호이다.
참고 \ (g의 [I] = \ 합계 \ limits_ {K} F [I] [K] \)

물론 전이 \ [F [I] [J ] = [! 반 [I] [J] \ {prod_ 아들 피의 \ [I]} (g [P] -f [P] [J]) \]

그러나 그러한 상태의 수입니다 \ (n 개 *의 m의 \)가 , 우리는 나무가 일부 색상이 없었 기억해야 발견, 대답의 다른 색상은 동일합니다.
이러한 방법으로 국가의 수를 절단 합니다 (N- * 케이 \)를 \ ,하지만 여전히 아주 큰, 그래서 우리는 유지할 수있는 트리 라인을 고려하십시오.

우리는 루트를 결합하는 서브 트리를 전송하는 경우
에 대해 \ (F [I] [J
] = (g [P] -f [P] [J]) * F [I] [J] \) 에 따라 이 우리는 트리 라인을 병합 할 수 있습니다.
단지 아버지가있는 경우 직접 받아
아버지의 아들 폭력 통합되었다
떨어져 곱하여 대괄호 넣어 만 아들 (- F [I] \를 J] \) 플러스 \ (g [P] * f를 [ 난] [J] \)
간격 더하기 의해 유지 간격을 필요로 유사한 기능을 유지할 수있다.
시간 복잡도는 약 \ (O ((N-K +) \ 로그 m) \) , 즉 코드 본다.

암호

나는 그것이 그대로두고 문제를 이길 쓴

#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]);
}

추천

출처www.cnblogs.com/BAJimH/p/10942994.html