2024.2.16

算是比较难的树形dp了吧。。。

我的跟题解做法不太一样,是维护2个数组 \(dp_{0/1,i}\)\(f_{0/1,i}\)。不太好说,看题解做法吧QAQ。

原神


#include <bits/stdc++.h>

typedef long long ll;

const ll SIZE = 10000 + 100;

ll N, M, a[SIZE];
ll C;

ll cnt = 1, head[SIZE], next[SIZE * 2], to[SIZE * 2];
ll value[SIZE * 2];
ll key[SIZE];

ll dp[2][SIZE];//dp[0][now] 表示now为中转站的最小花费 dp[1][now] 表示now不为中转站的最小花费

void AddEdge(ll u, ll v, ll w) {
    ++ cnt;
    next[cnt] = head[u];
    head[u] = cnt;
    to[cnt] = v;
    value[cnt] = w;
}

ll fat[SIZE];
ll f[2][SIZE];//f[0][now] 表示从儿子来的最小花费 f[1][now] 表示从父亲来的最小花费

void Dfs1(ll now, ll fa, ll dis) {
    ll sum = 0;

    f[0][now] = 0;
    for (ll i = head[now]; i; i = next[i]) {
        if (to[i] == fa)
            continue;
        Dfs1(to[i], now, dis + value[i]);
        sum += f[0][to[i]];
    }

    f[0][now] = std::min(sum + dis * key[now], std::min(dp[0][now], dp[1][now]));
}

std::pair<ll, ll> no;
ll temp[SIZE];

void Dfs3(ll now, ll fa, ll dis) {

    ll sum = 0;

    temp[now] = 0;
    for (ll i = head[now]; i; i = next[i]) {
        if (to[i] == fa || to[i] == no.first || to[i] == no.second) 
            continue;
        Dfs3(to[i], now, dis + value[i]);
        sum += temp[to[i]];
    }

    temp[now] = std::min(sum + dis * key[now], std::min(dp[0][now], dp[1][now]));
}

void Dfs2(ll now, ll fa, ll dis, ll from) {
    Dfs3(from, fat[from], dis);
    f[1][now] += temp[from];

    dp[0][from] = std::min(dp[0][from], f[1][now] + dp[1][now]);

    for (ll i = head[now]; i; i = next[i]) {
        if (to[i] == fa)
            continue;
        Dfs2(to[i], now, dis + value[i], from);
    }
    return;
}

void Dfs(ll now, ll fa) {
    ll tot = 0;

    dp[0][now] = dp[1][now] = 1e18;
    fat[now] = fa;

    for (ll i = head[now]; i; i = next[i]) {
        if (to[i] == fa)
            continue;
        tot ++;
        Dfs(to[i], now);
    }

    if (!tot) {
        dp[1][now] = C;
        return;
    }
    else {
        Dfs1(now, fa, 0);
        dp[1][now] = f[0][now] + C;
    }

    no.first = fa;

    for (ll i = head[now]; i; i = next[i]) {
        if (to[i] == fa)
            continue;
        
        no.second = to[i];
        Dfs2(to[i], now, value[i], now);
    }

}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    freopen("post.in", "r", stdin);
    freopen("post.out", "w", stdout);

    std::cin >> N >> M >> C;
    
    for (ll i = 1, u, v, w; i < N; ++ i) {
        std::cin >> u >> v >> w;
        AddEdge(u, v, w);
        AddEdge(v, u, w);
    }

    for (ll i = 1; i <= M; ++ i) {
        std::cin >> a[i];
        key[a[i]] ++;
    }   

    Dfs(1, 0);

    std::cout << std::min(dp[0][1], dp[1][1]) << '\n';

    return 0;
}

不会行列式和杜教筛

这个题好啊,我西索一下。

先知道一个性质:在分治过程中,每一层的长度只有两种可能。可以用归纳证一下。

我们先考虑单独特殊情况:选出的数是2的次幂(如:\(1000_{(2)},100_{(2)}\))。

那么我们的分治过程如下图:

那我们这个时候如果给 \(100_{(2)}\) 加上 \(1\) 呐?

那么就成了下图:

继续加一

有没有发现一些规律???

我们先设每一层原本的二进制长度为 \(p\)。(如:\(1001_{(2)}\)\(p\)\(4\))。并且设 \(x=10100_{(2)}\)

那么对于一个数 \(x\),我们在每一位上从左往右数第 \(2\)\(1\) 到最低位所表示的数(以 \(x\) 为例,是 \(100_{(2)}\),即 \(4_{(10)}\)),是在每一层里面产生的贡献是等效于 \(2^{p}\) 的数的个数 (与每一层的节点数取min),每一层里面剩下的节点都等效于 \(2^{p-1}\)

然后用线段树维护就行了。

崩坏:星穹铁道
#include <bits/stdc++.h>

typedef long long ll;

const int SIZE = 1e5 + 100;
const int mod = 998244353;

class Node {
public:
    int l, r;
    ll sum[2];
    int first[2];
};

int N, M;
int s[SIZE];
ll power2[SIZE];

class SegmentTree {
    #define lid (id << 1)
    #define rid (id << 1 | 1)

public:
    int tag[SIZE * 4];
    Node node[SIZE * 4];

private:
    Node pushup(Node lson, Node rson) {
        Node result;
        result.l = lson.l;
        result.r = rson.r;

        result.first[0] = std::min(lson.first[0], rson.first[0]);
        result.first[1] = std::min(lson.first[1], rson.first[1]);

        result.sum[0] = (lson.sum[0] * power2[rson.r - rson.l + 1] % mod + rson.sum[0]) % mod;
        result.sum[1] = (lson.sum[1] * power2[rson.r - rson.l + 1] % mod + rson.sum[1]) % mod;

        return result;
    }

    void Zero(Node &a) {
        a.first[0] = 1e9;
        a.sum[0] = 0;
        a.first[1] = a.l;
        a.sum[1] = (power2[a.r - a.l + 1] - 1 + mod) % mod;
    }

    void One(Node &a) {
        a.first[0] = a.l;
        a.sum[0] = (power2[a.r - a.l + 1] - 1 + mod) % mod;
        a.first[1] = 1e9;
        a.sum[1] = 0;
    }

    void Swap(Node &a) {
        std::swap(a.first[0], a.first[1]);
        std::swap(a.sum[0], a.sum[1]);
    }

    void Cover(int id, int New) {
        if (New == 1) {
            if (tag[id] == 2)
                One(node[id]), New = 3;
            else if (tag[id] == 3)
                Zero(node[id]), New = 2;
            else {
                Swap(node[id]);
                if (tag[id])
                    New = 0;
            }
        }
        else {
            if (New == 2)
                Zero(node[id]);
            else
                One(node[id]);
        }

        tag[id] = New;
    }

    void pushdown(int id) {
        if (tag[id] == 0)
            return;
        Cover(lid, tag[id]);
        Cover(rid, tag[id]);
        tag[id] = 0;
    }

public:
    void build(int id, int l, int r) {
        if (l == r) {
            if (s[l] == 1) {
                node[id].first[0] = l;
                node[id].first[1] = 1e9;
                node[id].sum[0] = 1;
                node[id].sum[1] = 0;
            }
            else {
                node[id].first[0] = 1e9;
                node[id].first[1] = l;
                node[id].sum[0] = 0;
                node[id].sum[1] = 1;
            }
            
            node[id].l = node[id].r = l;

            return;
        }

        int mid = (l + r) >> 1;

        build(lid, l, mid);
        build(rid, mid + 1, r);

        node[id] = pushup(node[lid], node[rid]);

        return;
    }

    void Update(int id, int l, int r, int askL, int askR, int flag) {
        if (askL <= l && r <= askR) {
            Cover(id, flag);
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(id);
        if (askL <= mid)
            Update(lid, l, mid, askL, askR, flag);
        if (mid + 1 <= askR)
            Update(rid, mid + 1, r, askL, askR, flag);
        node[id] = pushup(node[lid], node[rid]);
    }

    Node Query(int id, int l, int r, int askL, int askR) {
        if (askL <= l && r <= askR) 
            return node[id];

        int mid = (l + r) >> 1;
        pushdown(id);

        Node result;
        result.l = result.r = result.first[0] = result.first[1] = 1e9;
        result.sum[0] = result.sum[1] = 0;

        if (askL <= mid) {
            result = Query(lid, l, mid, askL, askR);
        }
        if (mid + 1 <= askR) {
            if (result.l == 1e9)
                result = Query(rid, mid + 1, r, askL, askR);
            else
                result = pushup(result, Query(rid, mid + 1, r, askL, askR));
        }
        return result;
    }

    #undef lid
    #undef rid
}tree;

std::string str;
ll treeSum[SIZE], prefix[SIZE], powerSum[SIZE];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    freopen("run.in", "r", stdin);
    freopen("run.out", "w", stdout);

    std::cin >> N >> M;
    power2[0] = 1;
    for (int i = 1; i <= N; ++ i) {
        power2[i] = power2[i - 1] * 2 % mod;
        treeSum[i] = (treeSum[i - 1] * 2 % mod + (1 + i - 1) * power2[i - 1] % mod) % mod;
        powerSum[i] = (powerSum[i - 1] + power2[i - 1]) % mod;
        prefix[i] = (prefix[i - 1] + power2[i - 1] * (1 + i - 1)) % mod;
    }

    std::cin >> str;
    std::reverse(str.begin(), str.end());
    for (int i = 1; i <= N; ++ i) {
        s[i] = str[i - 1] - '0';
    }
    tree.build(1, 1, N);

    for (int i = 1, opt, l, r; i <= M; ++ i) {
        std::cin >> opt >> l >> r;
        l = N - l + 1;
        r = N - r + 1;
        std::swap(l, r);

        if (opt == 4) {
            Node first = tree.Query(1, 1, N, l, r);
            if (first.first[0] == 1e9) {
                std::cout << 0 << '\n';
                continue;
            }

            ll answer = treeSum[first.r - first.first[0] + 1];
            Node second = tree.Query(1, 1, N, first.first[0] + 1, r);
            
            if (second.first[0] == 1e9) {
                std::cout << answer << '\n';
                continue;
            }

            ll val = second.sum[0];
            ll len1 = first.r - first.first[0] + 1;
            ll len2 = first.r - second.first[0] + 1;

            ll temp = power2[len1 - 1] * (len1 + len1 - len2 + 1) % mod * (len2) % mod * 499122177 % mod;
            temp = (temp + prefix[len1 - len2] * val % mod) % mod;
            answer = (answer - temp + mod) % mod;
            
            temp = (temp + power2[len1 - 1] * len2 % mod) % mod;
            temp = (temp + powerSum[len1 - len2] * val % mod) % mod * 2 % mod;
            
            answer = (answer + temp) % mod;
            answer = (answer + 2 * val) % mod;

            std::cout << answer << '\n';
        }
        else {
            tree.Update(1, 1, N, l, r, opt);
        }
    }

    return 0;
}
/*
5 1
01010
4 2 5
*/
posted @ 2024-02-17 07:29  觉清风  阅读(38)  评论(3编辑  收藏  举报