2017ccpc Hangzhou E. Master of Subgraph (point divide and conquer + tree dp + bitset)

The meaning of the question: Given a tree of n points, each point has a weight w[i], now we can select some connected points, and add the weights of the points selected by this point to get a with. Find which values ​​in [1, m] can be expressed as the sum of the weights of the selected points. Use 0101 sequence to output.

Ideas:

Consider point divide and conquer. First select the center of gravity of the tree, and consider the answer that must be selected at this point. Suppose I choose a certain point, then I must choose the father of this point. Now start recursing the tree. Recursively to a point each time, the bitset of this point is initialized to the bitset represented by the parent node and shifted right by w[x] bits. His meaning is that if the current point is selected, then his father must choose, that is, the answer to ask his father's current answer set combined with the weight of this point. When tracing back, the bitset represented by the father is the same as the bitset represented by the son. This is because after the other sons of the father later solve the problem, the information that the father has already obtained is used and combined to achieve the effect of connection through the father.

Finally, the answer to the tree rooted at the current divide-and-conquer center is the bitset represented by the divide-and-conquer center, so just continue to solve it recursively.

Time complexity O(nlogn⋅mw)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const double eps = 1e-11;
const int N = 3e3 + 10;
const int M = 1e5 + 10;

inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch))
        x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x * f;
}

///all表示当前子树的结点数
int n, all, sz[N], rt, rt2, a[N], siz[N], maxson[N], maxx;
vector<int>mp[N];
bitset<M>bit[N], ans;
bool vis[N];

void init() {
    ans.reset();
    for(int i = 1; i <= n; ++i) vis[i] = 0;
    for(int i = 1; i <= n; ++i) mp[i].clear();
}

void getrt(int u, int fa) {
    siz[u] = 1;
    maxson[u] = 0;
    int sz = mp[u].size();
    for(int i = 0; i < sz; ++i) {
        int v = mp[u][i];
        if(v == fa || vis[v]) continue;
        getrt(v, u);
        siz[u] = siz[u] + siz[v];
        maxson[u] = max(maxson[u], siz[v]);
    }
    maxson[u] = max(maxson[u], all - siz[u]);
    if((maxson[u] << 1) <= all) rt2 = rt, rt = u;
}

void calc(int u, int fa) {
    siz[u] = 1, bit[u] <<= a[u];
    int sz = mp[u].size();
    for(int i = 0; i < sz; ++i) {
        int v = mp[u][i];
        if(vis[v] || v == fa) continue;
        bit[v] = bit[u];
        calc(v, u);
        siz[u] += siz[v];
        bit[u] |= bit[v];
    }
}

void divide(int u) {
    vis[u] = 1;
    bit[u].reset(), bit[u].set(0);
    calc(u, 0);
    ans |= bit[u];
    int sz = mp[u].size();
    for(int i = 0; i < sz; ++i) {
        int v = mp[u][i];
        if(vis[v]) continue;
        rt = rt2 = 0;
        maxson[rt] = all = siz[v];
        getrt(v, 0);
        divide(rt);
    }
}

int main() {
    int t, m, u, v;
    t = read();
    while(t--) {
        n = read(), m = read();
        init();
        for(int i = 1; i < n; ++i) {
            u = read(), v = read();
            mp[u].push_back(v);
            mp[v].push_back(u);
        }
        for(int i = 1; i <= n; ++i) a[i] = read();
        rt = rt2 = 0;
        maxson[rt] = all = n;
        getrt(1, 0);
        getrt(rt, 0);
        divide(rt);
        for(int i = 1; i <= m; ++i) printf("%d", (int)ans[i]);
        printf("\n");
    }
    return 0;
}

 

Guess you like

Origin blog.csdn.net/weixin_43871207/article/details/109629931