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;
    }
    
    
  • 相关阅读:
    【背包专题】K
    【背包专题】J
    【背包专题】H
    【背包专题】C
    5972: 【递归入门】全排列
    51nod 1136 欧拉函数【数论】
    【背包专题】G
    【背包专题】I
    【背包专题】F
    各浏览器的Hack写法
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10965557.html
Copyright © 2011-2022 走看看