zoukankan      html  css  js  c++  java
  • 【LOJ】#3044. 「ZJOI2019」Minimax 搜索

    LOJ#3044. 「ZJOI2019」Minimax 搜索

    一个菜鸡的50pts暴力

    (dp[u][j])表示(u)(j)次操作能使得(u)的大小改变的方案数

    设每个点的初始答案是(S[u])

    每个数大小只和(S[1])的大小关系有关

    于是每个数的状态设为-1(比S[1]小),1(比S[1]大),0(和S[1]一样)

    状态里设的改变是指在这三种状态里的一种变为另一种

    如果(S[u] == S[1])或者(u)点取max但是(S[u] < S[1])(u)点取min但是(S[u] > S[1])

    这个时候子树里任意一个点改变(u)就会改变,统计两个序列的后缀和并且和当前位置更新即可(因为操作数选最小的那个)

    否则的话就是子树里所有与(S[u] < S[1])真假性不同的点都必须改变,剩下的点选了也不用变,统计前缀和并且和当前位置更新(因为操作数选最大的那个)

    复杂度(O(n^2))

    LOJ提交记录

    神仙的100pts正解

    我们统计前缀操作,也就是对于一个(i)统计(pre[i])是小于等于(i)次操作的方案数

    我们找出答案都是(S[1])的那条链,容易发现这条链上奇数位置的点挂着的子树,其中的叶子都必须尽量改大(大于(S[1])),而偶数位置的点挂着的子树里面的叶子,都必须尽量改小(小于(S[1])

    改成大于(S[1])的最少操作是改成(S[1] + 1),小于(S[1])的最少操作是改成(S[1] - 1)

    以下把(<S[1 ])标成0,$ >S[1]$标成1

    于是设(dp[i][0 / 1])表示第(i)个点选了一个点集后(i)的答案是0或者是1

    转移的话就是设(t = dep[i] & 1)

    $dp[u][t oplus 1] = prod dp[v][t oplus 1] $

    (dp[u][t] = 2^{leaf[u]} - dp[u][t oplus 1])

    最后我们要求的是链上的点不变的方案数,再用总的方案数减去

    我们可以只记一个,而我们要用的是(dp[u][t])于是我们只记(dp[u][t])

    从小到大枚举最小的操作数,每次可以至多有两个点变为可以更改

    发现这个式子可以动态dp转移,于是我们设常数项是(2^{leaf[u]}),系数是(-prod dp[v][t oplus 1])其中v是(u)所有的轻儿子

    而叶子节点的值,在变更的时候看一下是否初始值是(S[u] < S[1])而且是需要尽量大的子树((S[u] > S[1])而且需要尽量小的子树),这个时候可以把叶子节点的常数项改成1,否则叶子节点的值就不需要改变了

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define eps 1e-10
    #define MAXN 200005
    #define ba 47
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef unsigned int u32;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
        	if(c == '-') f = -1;
        	c = getchar();
        }
        while(c >= '0' && c <= '9') {
        	res = res * 10 +c - '0';
        	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
        	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    const int MOD = 998244353;
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void update(int &a,int b) {
        a = inc(a,b);
    }
    int fpow(int x,int c) {
        int res = 1,t = x;
        while(c) {
            if(c & 1) res = mul(res,t);
            t = mul(t,t);
            c >>= 1;
        }
        return res;
    }
    
    
    struct Edge {
        int to,next;
    }E[MAXN * 2];
    struct val {
        int v,zero;
        val(int a = 0) {
            v = max(a,1);zero = !a;
        }
        friend val operator * (const val &a,const val &b) {
            val c;
            c.v = mul(a.v,b.v);
            c.zero = a.zero + b.zero;
            return c;
        }
        friend val operator / (const val &a,const val &b) {
            val c;
            c.v = mul(a.v,fpow(b.v,MOD - 2));
            c.zero = a.zero - b.zero;
            return c;
        }
        int getval() {
            if(zero) return 0;
            else return v;
        }
    }ms[MAXN],all;
    struct node {
        int l,r;pair<int,int> rec;
    }tr[MAXN * 4];
    int head[MAXN],sumE,N,L,R;
    int dfn[MAXN],siz[MAXN],son[MAXN],dep[MAXN],idx,lef[MAXN],fa[MAXN];
    int top[MAXN],bot[MAXN],line[MAXN];
    int S[MAXN],ans[MAXN];
    int dp[MAXN][2];
    bool nd[MAXN];
    void add(int u,int v) {
        E[++sumE].to = v;
        E[sumE].next = head[u];
        head[u] = sumE;
    }
    void dfs(int u) {
        dep[u] = dep[fa[u]] + 1;
        if(dep[u] % 2 == 0) S[u] = N;
        siz[u] = 1;
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                fa[v] = u;
                dfs(v);
                siz[u] += siz[v];
                if(dep[u] & 1) S[u] = max(S[u],S[v]);
                else S[u] = min(S[u],S[v]);
                if(siz[v] > siz[son[u]]) son[u] = v;
            }
        }
        if(!son[u]) {
            S[u] = u;return;
        }
    }
    void dfs2(int u,int p = 0) {
        if(S[u] != S[1]) {
            dfn[u] = ++idx;
            if(!top[u]) top[u] = u;
            line[idx] = u;
        }
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u]) {
                if(S[u] == S[1] && S[1] == S[v]) son[u] = v;
            }
        }
        if(!son[u]) {
            lef[u]++;
            bot[u] = u;
            nd[u] = p;
            if(S[u] == S[1]) {dp[u][0] = 1;ms[u] = 1;}
            else {
                if(S[u] > S[1]) dp[u][1] = 2;
                else dp[u][0] = 2;
            }
            return;
        }
        top[son[u]] = top[u];
        dfs2(son[u],p);
        bot[u] = bot[son[u]];
        lef[u] += lef[son[u]];
        if(S[u] == S[1]) p = dep[u] & 1;
        ms[u] = 1;int t = dep[u] & 1;
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            if(v != fa[u] && v != son[u]) {
                dfs2(v,p);
                lef[u] += lef[v];
                ms[u] = ms[u] * dp[v][t ^ 1];
            }
        }
        dp[u][t ^ 1] = mul(ms[u].getval(),dp[son[u]][t ^ 1]);
        dp[u][t] = inc(fpow(2,lef[u]),MOD - dp[u][t ^ 1]);
        if(S[u] == S[1]) all = all * ms[u];
    }
    pii Merge(pii a,pii b) {
        pii c;
        c.fi = mul(a.fi,b.fi);
        c.se = inc(mul(a.fi,b.se),a.se);
        return c;
    }
    void updateTr(int u) {
        tr[u].rec = Merge(tr[u << 1].rec,tr[u << 1 | 1].rec);
    }
    void build(int u,int l,int r) {
        tr[u].l = l;tr[u].r = r;
        if(l == r) {
            int t = line[l];
            tr[u].rec.fi = (MOD - ms[t].getval()) % MOD;tr[u].rec.se = fpow(2,lef[t]);
            if(!son[t]) tr[u].rec.se = dp[t][dep[t] & 1];
            return;
        }
        int mid = (l + r) >> 1;
        build(u << 1,l,mid);
        build(u << 1 | 1,mid + 1,r);
        updateTr(u);
    }
    void Change(int u,int pos) {
        if(tr[u].l == tr[u].r) {
            int t = line[pos];
            if(!son[t]) {
                if((S[t] > S[1]) != nd[t]) tr[u].rec.se = 1;
            }
            else tr[u].rec.fi = (MOD - ms[t].getval()) % MOD;
            return;
        }
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(pos <= mid) Change(u << 1,pos);
        else Change(u << 1 | 1,pos);
        updateTr(u);
    }
    pii Query(int u,int l,int r) {
        if(tr[u].l == l && tr[u].r == r) return tr[u].rec;
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(r <= mid) return Query(u << 1,l,r);
        else if(l > mid) return Query(u << 1 |1,l,r);
        else return Merge(Query(u << 1,l,mid),Query(u << 1 | 1,mid + 1,r));
    }
    void Process(int u) {
        while(S[u] != S[1]) {
            int ori = Query(1,dfn[top[u]],dfn[bot[u]]).se;
            Change(1,dfn[u]);
            int f = fa[top[u]],nw = Query(1,dfn[top[u]],dfn[bot[u]]).se;
            if(S[f] == S[1]) all = all / ms[f];
            ms[f] = ms[f] / ori;
            ms[f] = ms[f] * nw;
            if(S[f] == S[1]) all = all * ms[f];
            u = f;
        }
    }
    void Init() {
        read(N);read(L);read(R);
        int a,b;
        for(int i = 1 ; i < N ; ++i) {
            read(a);read(b);
            add(a,b);add(b,a);
        }
    }
    void Solve() {
        all = 1;
        dfs(1);
        dfs2(1);
        ans[1] = fpow(2,lef[1] - 1);
        build(1,1,idx);
        int pw = fpow(2,lef[1]);
        ans[N] = pw - 1;
        for(int i = 2 ; i < N ; ++i) {
            if(S[1] + 1 - i > 1 && !son[S[1] + 1 - i]) {Process(S[1] + 1 - i);}
            if(S[1] - 1 + i <= N && !son[S[1] - 1 + i]) {Process(S[1] - 1 + i);}
            ans[i] = inc(pw,MOD - all.getval());
        }
        for(int i = N ; i >= 1 ; --i) {
            ans[i] = inc(ans[i],MOD - ans[i - 1]);
        }
        for(int i = L ; i <= R ; ++i) {
            out(ans[i]);space;
        }
        enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
    
  • 相关阅读:
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 47 全排列 II(二)
    Java实现 LeetCode 47 全排列 II(二)
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10965557.html
Copyright © 2011-2022 走看看