ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UOJ#468. 【ZJOI2019】Minimax搜索 动态DP

2019-07-11 15:07:11  阅读:286  来源: 互联网

标签:return 468 val int Minimax depth ZJOI2019 dp mod


原文链接www.cnblogs.com/zhouzhendong/p/UOJ468.html

前言

毒瘤题

题解

首先,将问题稍加转化,将“等于k”转化为“小于等于k”减去“小于k”。

然后,考虑在有一个变化量限制k时,所有的叶子会怎样变化。

我们称原本根的权值对应的节点到根的路径为“主链”,那么,只要主链的任何一个节点的权值发生变化,那么根节点权值就发生变化。

我们称一个主链上的节点的在主链上的儿子为“主儿子”。

对于主链上的一个节点,假设他深度为奇数,那么他的所有子树中,除了主儿子所在子树以外的所有叶子节点都会加上k。否则,假设他深度为偶数,那么这些叶子节点会减去k。

于是,接下来我们就可以得到一个 \(O(n)\) 的 DP 方法。即

对于深度为奇数的主链的子树, \(dp[x][0]\)、\(dp[x][1]\) 分别表示在子树x的所有叶子节点集合操作时,有 \(dp[x][1]\) 个集合可以使得 x 的权值大于 1 号点原先的权值,有 \(dp[x][0]\) 个不能。

对于深度为偶数的主链的子树, \(dp[x][1]\)、\(dp[x][0]\) 分别表示在子树x的所有叶子节点集合操作时,有 \(dp[x][1]\) 个集合可以使得 x 的权值小于 1 号点原先的权值,有 \(dp[x][1]\) 个不能。

请读者自行列出 DP 转移。

事实上,这种 DP 状态是可以简化的。由于对于一个 x,\(dp[x][0]+dp[x][1]\) 是固定的,所以我们只需要记一个。虽然这不影响得分。

至此,我们得到了一个单次 DP \(O(n)\),总时间复杂度 \(O((R-L)\cdot n)\) 的做法。

我们发现,当k的值从小到大不断变大时,只会有 \(O(n)\) 个叶子的 DP 值发生变化,每次变化会影响它到根的路径。

简单分析即可发现这里可以用动态DP来维护。

于是我们就得到了一个 \(O(n\log ^ 2 n)\) 的做法。

注意维护的时候可以会遇到乘0和除0的情况,注意特判。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof x)
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define next Next
#define outval(x) cerr<<#x" = "<<x<<endl
#define outtag(x) cerr<<"-----------------"#x"-----------------\n"
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
                    For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int,int> pii;
LL read(){
    LL x=0,f=0;
    char ch=getchar();
    while (!isdigit(ch))
        f=ch=='-',ch=getchar();
    while (isdigit(ch))
        x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?-x:x;
}
const int N=200005,mod=998244353;
int Pow(int x,int y){
    int ans=1;
    for (;y;y>>=1,x=(LL)x*x%mod)
        if (y&1)
            ans=(LL)ans*x%mod;
    return ans;
}
void Add(int &x,int y){
    if ((x+=y)>=mod)
        x-=mod;
}
void Del(int &x,int y){
    if ((x-=y)<0)
        x+=mod;
}
int Add(int x){
    return x>=mod?x-mod:x;
}
int Del(int x){
    return x<0?x+mod:x;
}
int n,qL,qR;
vector <int> e[N];
int depth[N],size[N],son[N],val[N];
int fa[N],leaf[N],clf[N],pw2[N],clf2[N];
int fun(int k,int a,int b){
    return k&1?max(a,b):min(a,b);
}
void dfs(int x,int pre,int d){
    depth[x]=d,size[x]=1,son[x]=0,fa[x]=pre;
    if (e[x].size()==1&&d>1)
        val[x]=x,leaf[x]=clf[x]=1;
    else
        val[x]=d&1?0:n;
    for (auto y : e[x])
        if (y!=pre){
            dfs(y,x,d+1);
            clf[x]+=clf[y];
            size[x]+=size[y];
            val[x]=fun(d,val[x],val[y]);
            if (!son[x]||size[y]>size[son[x]])
                son[x]=y;
        }
}
int next[N],fad[N];
void dfs2(int x,int d){
    fad[x]=d;
    for (auto y : e[x])
        if (y!=fa[x]&&y!=next[x])
            dfs2(y,d);
}
void GetNext(){
    int x=val[1];
    for (int y=fa[x];y;x=y,y=fa[x])
        next[y]=x,dfs2(y,depth[y]);
}
int top[N],I[N],aI[N],Time=0;
void GetTop(int x,int tp){
    top[x]=tp,I[x]=++Time,aI[Time]=x;
    if (son[x]&&son[x]!=next[x])
        GetTop(son[x],tp);
    for (auto y : e[x])
        if (!I[y])
            GetTop(y,y);
}
int ans[N];
int dp[N];
int delta;
void DP(int x){
    dp[x]=0;
    if (x==val[1]){
        dp[x]=1;
        return;
    }
    if (leaf[x]){
        if (fad[x]&1){
            dp[x]+=(x+delta>val[1])==(depth[x]&1);
            dp[x]+=(x>val[1])==(depth[x]&1);
        }
        else {
            dp[x]+=(x-delta>=val[1])==(depth[x]&1);
            dp[x]+=(x>=val[1])==(depth[x]&1);
        }
        return;
    }
    dp[x]=1;
    for (auto y : e[x])
        if (y!=fa[x]){
            DP(y);
            if (y!=next[x])
                dp[x]=(LL)dp[x]*dp[y]%mod;
        }
    dp[x]=Del(pw2[clf2[x]]-dp[x]);
}
struct int0{
    int v,c;
    int0(){}
    int0(int _v,int _c){
        v=_v,c=_c;
    }
    int f(){
        return c?0:v;
    }
    void operator *= (int x){
        if (!x)
            c++;
        else
            v=(LL)v*x%mod;
    }
    void operator /= (int x){
        if (!x)
            c--;
        else
            v=(LL)v*Pow(x,mod-2)%mod;
    }
}v2[N],now;
int0 Get(){
    int0 ans=int0(1,0);
    for (int x=val[1];x;x=fa[x])
        ans*=Del(pw2[clf2[x]]-dp[x]);
    return ans;
}
struct fuck{
    int a,b;
    fuck(){}
    fuck(int _a,int _b){
        a=_a,b=_b;
    }
    friend fuck operator * (fuck x,fuck y){
        return fuck((LL)x.a*y.a%mod,((LL)x.a*y.b+x.b)%mod);
    }
    int calc(int x){
        return ((LL)a*x+b)%mod;
    }
}v[N];
int mxd[N];
namespace Seg{
    fuck s[N<<2];
    void Build(int rt,int L,int R){
        if (L==R)
            return (void)(s[rt]=v[aI[L]]);
        int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
        Build(ls,L,mid);
        Build(rs,mid+1,R);
        s[rt]=s[ls]*s[rs];
    }
    void update(int rt,int L,int R,int x,fuck v){
        if (L==R)
            return (void)(s[rt]=v);
        int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
        if (x<=mid)
            update(ls,L,mid,x,v);
        else
            update(rs,mid+1,R,x,v);
        s[rt]=s[ls]*s[rs];
    }
    fuck query(int rt,int L,int R,int xL,int xR){
        if (R<xL||L>xR)
            return fuck(1,0);
        if (xL<=L&&R<=xR)
            return s[rt];
        int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
        return query(ls,L,mid,xL,xR)*query(rs,mid+1,R,xL,xR);
    }
}
void update(int x){
    while (1){
        Seg::update(1,1,n,I[x],v[x]);
        x=top[x];
        int f=fa[x];
        if (val[x]!=val[1])
            v2[f]/=dp[x];
        else
            now/=Del(pw2[clf2[x]]-dp[x]);
        dp[x]=Seg::query(1,1,n,I[x],I[mxd[x]]).calc(1);
        if (val[x]!=val[1])
            v2[f]*=dp[x],v[f].a=v2[f].f(),x=f;
        else {
            now*=Del(pw2[clf2[x]]-dp[x]);
            break;
        }
    }
}
vector <int> upds[N];
int main(){
    n=read(),qL=read(),qR=read();
    pw2[0]=1;
    For(i,1,n)
        pw2[i]=Add(pw2[i-1]<<1);
    For(i,1,n-1){
        int x=read(),y=read();
        e[x].pb(y),e[y].pb(x);
    }
    dfs(1,0,1);
    GetNext();
    GetTop(1,1);
    For(i,1,n)
        clf2[i]=clf[i];
    for (int x=val[1];x;x=fa[x])
        clf2[x]-=clf[next[x]];
    delta=1,DP(1),now=Get(),ans[1]=Del(pw2[clf[1]]-now.f());
    For(x,1,n){
        if (leaf[x])
            v[x]=fuck(0,dp[x]);
        else {
            v2[x]=int0(Del(-1),0);
            for (auto y : e[x])
                if (y!=fa[x]&&y!=next[x]&&y!=son[x])
                    v2[x]*=dp[y];
            v[x]=fuck(v2[x].f(),pw2[clf2[x]]);
        }
    }
    For(x,1,n)
        if (top[x]==x)
            mxd[x]=x;
    For(x,1,n)
        if (depth[x]>depth[mxd[top[x]]])
            mxd[top[x]]=x;
    Seg::Build(1,1,n);
    For(i,1,n){
        if (!leaf[i]||i==val[1])
            continue;
        if (fad[i]&1){
            if (i<val[1])
                upds[val[1]-i+1].pb(i);
        }
        else {
            if (i>val[1])
                upds[i-val[1]+1].pb(i);
        }
    }
    For(i,2,n-1){
        delta=i;
        for (auto x : upds[i]){
            int tmp=0;
            if (fad[x]&1){
                tmp+=(x+delta>val[1])==(depth[x]&1);
                tmp+=(x>val[1])==(depth[x]&1);
            }
            else {
                tmp+=(x-delta>=val[1])==(depth[x]&1);
                tmp+=(x>=val[1])==(depth[x]&1);
            }
            v[x]=fuck(0,tmp);
            update(x);
        }
        ans[i]=Del(pw2[clf[1]]-now.f());
    }
    ans[n]=Del(pw2[clf[1]]-1);
    For(i,qL,qR)
        printf("%d ",Del(ans[i]-ans[i-1]));
    puts("");
    return 0;
}

标签:return,468,val,int,Minimax,depth,ZJOI2019,dp,mod
来源: https://www.cnblogs.com/zhouzhendong/p/UOJ468.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有