n^2log动态规划

新生赛题
F. tree options
如果能想到弱化版操作为每个节点值都小于等于0,就很容易想到n方log的做法。
但是回到原题会发现单调性有变化,不能直接二分。由于奇数轮数和偶数轮数分别有自己的单调性,就可以对奇偶轮数分别二分然后枚举非整轮部分。dp算每个点还要多少次能变为合法点。
题解有复杂度优化待学。

代码在好几个地方写挂了
1.ans大小
2.对奇数偶数轮数二分的方法
3.不知道为什么函数传值比开数组快了1s。。

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define pii pair<int, int>
#define mkp make_pair
#define LL long long
#define ll long long
#define endl '\n'

const int N = 2e3 + 10, inf = 1e9;


LL n, rt, f[N], a[N], p, nw;
vector<int>E[N];
 
void dfs(int x, int fa) {
    f[x] = a[x];
    LL tmp = nw + (x <= p);
    for (int i:E[x]){
        if(i == fa) continue;
        dfs(i, x);
        f[x] += f[i];
    }
    f[x] = (f[x]-tmp > 0) ?(f[x] - tmp) : (f[x] - tmp & 1);
    // if(p == 0)cout << f[x] << ' '<< x << 'x' << tmp << endl;
}

void solve()
{
    cin >> n >> rt;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        E[u].push_back(v);
        E[v].push_back(u);
    }
    if (n == 1) {
        cout << a[1] << endl;
        return;
    }
    LL ans = 1ll*inf*N;
    for(int i = 0; i < n; i++)
    {
        p = i;
        LL l = 0, r = inf, mid = (l+r)/2;
        while(l < r) {
            nw = mid*2+1;
            dfs(rt, 0);
            if(f[rt]) l = mid + 1;
            else r = mid;
            mid = (l + r) / 2;
        }
        ans = min(ans, (mid * 2 + 1) * n + i);
        l = 0, r = inf, mid = (l + r) / 2;
        while(l < r) {
            nw = mid*2;
            dfs(rt, 0);
            if(f[rt]) l = mid + 1;
            else r = mid;
            mid = (l + r) / 2;
        }
        ans = min(ans, mid*2*n + i);
    }
    if(ans == 1ll*inf*N)cout<<-1<<endl;
    else cout<<ans<<endl;
    for (int i = 0;i <= n; i++)E[i].clear();
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
}
/*
1
3 2
2 1 3
2 1
3 2

*/
posted @ 2024-11-18 10:53  lyrrr  阅读(1)  评论(0编辑  收藏  举报