2019杭电/牛客多校待补题和已补题

rt

2019杭电/牛客多校待补题和已补题

    • HDU第八场
      • HDU6662 Acesrc and Travel 树形DP
      • hdu 6638 Snowy Smile

HDU第八场

HDU6662 Acesrc and Travel 树形DP

题意:

  • A,B两个人,每个节点有两个属性 a i , b i a_i,b_i ai,bi,A先选一个节点,B选相邻下一个节点,交替选直到没法选。A想让 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)最大,B想让 ∑ ( b i − a i ) \sum (b_i-a_i) (biai)最大。两人都足够聪明,问最后 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)是多少。

分析:

  • 上面规矩的意思可以说:B想让 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)最小,A想让 ∑ ( b i − a i ) \sum (b_i-a_i) (biai)最小。
  • A选了 u u u,若此时 u u u的儿子全是叶子,B肯定会帮A选 ∑ ( b i − a i ) \sum (b_i-a_i) (biai)最大的路径,此贡献是 a u − b u − m a x ( ∑ ( b i − a i ) ) a_u-b_u- max(\sum (b_i-a_i)) aubumax((biai)),这也是 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)最小的路径。
  • B选了 u u u,若此时 u u u的儿子全是叶子,A肯定会帮B选 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)最大的路径,此贡献是 a u − b u + m a x ( ∑ ( a i − b i ) ) a_u-b_u+ max(\sum (a_i-b_i)) aubu+max((aibi)),这也是 ∑ ( b i − a i ) \sum (b_i-a_i) (biai)最小的路径。
  • 记录 d p 1 [ i ] [ 0 ] dp1[i][0] dp1[i][0]表示双方采取最优策略下 i i i子树向下路径中 ∑ ( a i − b i ) \sum (a_i-b_i) (aibi)的最小值, d p 1 [ i ] [ 1 ] dp1[i][1] dp1[i][1]为次小值; d p 2 [ i ] [ 0 ] dp2[i][0] dp2[i][0]表示双方采取最优策略下 i i i子树向下中 ∑ ( b i − a i ) \sum (b_i-a_i) (biai)的最小值, d p 2 [ i ] [ 1 ] dp2[i][1] dp2[i][1]为次小值。
  • 若以节点 x x x为根开始做上面树形DP,则 d p 1 [ x ] [ 0 ] dp1[x][0] dp1[x][0]为此时的答案。为统计出每个节点为根时的答案,我们先随便从一个点开始一遍树形DP,然后从同一点开始做换根DP(也就是用父亲的信息更新自己作为根时的贡献。
  • 转移方程: d p 1 [ u ] [ 0 ] = a r [ u ] − b r [ u ] − m a x ( d p 2 [ v ] [ 0 ] )    v ∈ s o n [ u ] dp1[u][0] = ar[u]-br[u] - max(dp2[v][0])\; v\in son[u] dp1[u][0]=ar[u]br[u]max(dp2[v][0])vson[u] d p 2 [ u ] [ 0 ] = a r [ u ] − b r [ u ] − m a x ( d p 1 [ v ] [ 0 ] )    v ∈ s o n [ u ] dp2[u][0] = ar[u]-br[u] - max(dp1[v][0])\; v\in son[u] dp2[u][0]=ar[u]br[u]max(dp1[v][0])vson[u]
  • 换根DP时:双方最优策略下:对每个节点记录它向上路径中最小的 ∑ ( a i − b i ) \sum(a_i-b_i) (aibi)=TMP[u],min(dp1[u][0],TMP[u])是u为根时的答案。
  • 为记录TMP[u]还需记录sta[u]表示u节点向上路径中最大的 ∑ ( a i − b i ) \sum(a_i-b_i) (aibi).
/*
在AB足够聪明的情况下,A要a-b最大值,答案是dp1[u][0]=min(\sum (a_i-b_i)) = ar[u]-br[u]-dp2[u][0],在u的儿子中减去min(\sum b_i-a_i)也就是加上max(\sum a_i-b_i)),用最大的\sum a_i-b_i更新答案即可。dp2[u][0]也是用最大的$\sum b_i-a_i$更新答案。
换根DP时:双方最优策略下:对每个节点记录它向上路径中最小的$\sum(a_i-b_i)$=TMP[u],min(dp1[u][0],TMP[u])是u为根时的答案。
为记录TMP[u]还需记录sta[u]表示u节点向上路径中最大的$\sum(a_i-b_i)$.

本题用最大值来更新最小值,和用最小值来更新最大值,答案是最小值,这有点博弈感觉把。
*/
const int MXN = 1e6 + 7;
const int MXE = 1e6 + 7;
int n, m;
LL ar[MXN], br[MXN];
vector<int> mp[MXN];
LL dp1[MXN][2], dp2[MXN][2], TMP[MXN];
int son[MXN][2], fa[MXN], num[MXN];
LL ans;
void dfs1(int u, int ba) {//a - b的minsum, b - a的minsum
    dp1[u][0] = dp1[u][1] = INFLL;
    dp2[u][0] = dp2[u][1] = INFLL;
    fa[u] = ba;num[u] = 0;
    for(auto v: mp[u]) {
        if(v == ba) continue;
        dfs1(v, u);
        num[u]++;
        if(ar[u] - br[u] - dp2[v][0] < dp1[u][0]) {
            son[u][0] = v;
            dp1[u][1] = dp1[u][0];
            dp1[u][0] = ar[u] - br[u] - dp2[v][0];
        }else dp1[u][1] = sml(dp1[u][1], ar[u] - br[u] - dp2[v][0]);
        if(br[u] - ar[u] - dp1[v][0] < dp2[u][0]) {
            son[u][1] = v;
            dp2[u][1] = dp2[u][0];
            dp2[u][0] = br[u] - ar[u] - dp1[v][0];
        }else dp2[u][1] = sml(dp2[u][1], br[u] - ar[u] - dp1[v][0]);
    }
    if(num[u] == 0) dp1[u][0] = dp1[u][1] = ar[u] - br[u], dp2[u][0] = dp2[u][1] = br[u] - ar[u];
}
LL tmp, sta[MXN];
void dfs2(int u, int ba) {
	for(auto v: mp[u]) {
		if(v == ba) continue;
		tmp = dp1[v][0];
		if(v == son[u][1]) {
			tmp = dp2[u][1];
		}else {
			tmp = dp2[u][0];
		}
		int aim = 4;
//		if(v == aim) debug(tmp, u, mp[u].size())
		if(u != 1) tmp = sml(tmp, -sta[u]);//a-b max
		if(num[u] == 1) {
		    if(num[v] == 0) ans = big(ans,  TMP[v] = ar[v] - br[v] + sta[u]);
		    else ans = big(ans, sml(dp1[v][0], TMP[v] = ar[v] - br[v] + sta[u]));
//		    debug(u, v, ans, dp1[v][0], ar[v] - br[v], sta[u])
		}
		else {
		    if(num[v] == 0) ans = big(ans, TMP[v] = ar[v] - br[v] - tmp);
		    else ans = big(ans, sml(dp1[v][0], TMP[v] = ar[v] - br[v] - tmp));
		}
//		if(v == aim) debug(tmp, sta[u], mp[v].size())
		if(v == son[u][0]) {
		    tmp = dp1[u][1];
		}else {
		    tmp = dp1[u][0];
		}// a-b max  b-a min
		if(num[u] == 1) sta[v] = ar[v] - br[v] + TMP[u];
		else {
		    if(u == 1) sta[v] = ar[v] - br[v] + tmp;
		    else sta[v] = ar[v] - br[v] + sml(tmp, TMP[u]);//a-b max b - a min
		}
//		debug(u, v, ans, son[u][1]);
		dfs2(v, u);
	}
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    int tim = read();
    while(tim --) {
        n = read();
        for(int i = 1; i <= n; ++i) ar[i] = read(), mp[i].clear();
        for(int i = 1; i <= n; ++i) br[i] = read();
        for(int i = 1, a, b; i < n; ++i) {
            a = read(), b = read();
            mp[a].eb(b), mp[b].eb(a);
        }
        dfs1(1, 0);
        for(int i = 1; i <= n; ++i) {
//            printf("%d %d %lld %lld %lld %lld\n", son[i][0], son[i][1], dp1[i][0], dp1[i][1], dp2[i][0], dp2[i][1]);
        }
        sta[0] = -INFLL;
		TMP[1] = sta[1] = ar[1] - br[1];
		ans = dp1[1][0];
		dfs2(1, 0);//max minnum
		printf("%lld\n", ans);
    }
#ifndef ONLINE_JUDGE
//    cout << "time cost:" << 1.0*(clock())/CLOCKS_PER_SEC << "\n";
#endif
    return 0;
}
/*
6
7
-1 -1 -1 0 1 1 1
0 0 0 0 0 0 0
1 2
2 3
3 4
4 5
5 6
6 7
5
-100 1 -100 1 1
0 0 0 0 0
1 2
1 3
2 4
2 5
3
1 1 1
0 2 3
1 2
1 3
5
1 1 1 2 4
0 2 3 3 2
1 2
1 3
2 4
2 5
11
1 1 1 2 4 4 3 2 5 6 2
0 2 3 3 2 0 3 2 6 4 3
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
8 10
8 11
11
2 4 5 3 6 8 1 0 6 4 3
9 3 5 0 6 1 3 5 7 9 0
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
8 10
8 11
*/

hdu 6638 Snowy Smile

经典思维好题
2000 2000 2000个点 ( x , y ) , − 1 e 9 ≤ x , y ≤ 1 e 9 (x,y),-1e9\le x,y\le 1e9 (x,y),1e9x,y1e9,点权 a i a_i ai,任选一个矩阵,其特征值为内部点权和,求最大特征值。

#pragma comment(linker, "/STACK:102400000,102400000")
//#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define fi first
#define se second
#define endl '\n'
#define o2(x) (x)*(x)
#define BASE_MAX 31
#define mk make_pair
#define eb push_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false); cin.tie(0)
#define my_unique(x) sort(all(x)),x.erase(unique(all(x)),x.end())
using namespace std;
#pragma optimize("-O3")
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
inline LL read() {
    LL x = 0;int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
inline void write(LL x, bool f) {
    if (x == 0) {putchar('0'); if(f)putchar('\n');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('\n');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template<class T>T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<class T>T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<typename T, typename ...R>T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
void debug_out() { cerr << '\n'; }
template<typename T, typename ...R>void debug_out(const T &f, const R &...r) {cerr << f << " ";debug_out(r...);}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);


const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 1e9 + 7;
const int MOD = 1e9 + 7;//998244353
const int INF = 0x3f3f3f3f;
const int MXN = 2e3 + 7;
const int MXE = 2e5 + 7;
int n, m;
#ifndef ONLINE_JUDGE
    clock_t p0 = clock();
#endif
struct lp{
    int x, y;
    LL val;
}cw[MXN];
int ar[MXN];
LL ans;
LL sum[MXN], mp[MXN][MXN];
vector<pair<int ,LL> > vs[MXN];
#define lson rt<<1
#define rson rt<<1|1
LL all[MXN<<2], lsum[MXN<<2], rsum[MXN<<2], Sum[MXN<<2];
void push_up(int rt) {
    all[rt] = big(all[lson], all[rson], rsum[lson] + lsum[rson], Sum[lson] + lsum[rson], Sum[rson] + rsum[lson], Sum[lson] + Sum[rson]);
    lsum[rt] = big(lsum[lson], Sum[lson] + lsum[rson]);
    rsum[rt] = big(rsum[rson], Sum[rson] + rsum[lson]);
    Sum[rt] = Sum[lson] + Sum[rson];
}
void build(int l, int r, int rt) {
    if(l == r) {
        all[rt] = lsum[rt] = rsum[rt] = Sum[rt] = sum[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt<<1), build(mid + 1, r, rt<<1|1);
    push_up(rt);
}
void update(int p, LL v, int l, int r, int rt) {
    if(l == r) {
        Sum[rt] += v;
        all[rt] = lsum[rt] = rsum[rt] = Sum[rt];
        return;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) update(p, v, l, mid, lson);
    else update(p, v, mid + 1, r, rson);
    push_up(rt);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    int tim = read();
    while(tim --) {
        n = read();
        ans = 0;
        int k = 0;
        for(int i = 1; i <= n; ++i) cw[i].x = read(), cw[i].y = read(), ar[k++] = cw[i].x, cw[i].val = read();
        sort(ar, ar + k);
        k = unique(ar, ar + k) - ar;
        for(int i = 1; i <= n; ++i) cw[i].x = lower_bound(ar, ar + k, cw[i].x) - ar + 1;
        int p = 0;
        for(int i = 1; i <= n; ++i) ar[p++] = cw[i].y;
        sort(ar, ar + p);
        p = unique(ar, ar + p) - ar;
        for(int i = 1; i <= n; ++i) cw[i].y = lower_bound(ar, ar + p, cw[i].y) - ar + 1;
        for(int i = 1; i <= n; ++i) mp[cw[i].x][cw[i].y] += cw[i].val;
        for(int i = 0; i <= p; ++i) vs[i].clear();
        for(int i = 0; i <= k; ++i) for(int j = 0; j <= p; ++j) {
            ans = big(ans, mp[i][j]);
            if(mp[i][j]) vs[j].eb(mk(i, mp[i][j]));
        }
//        for(int i = 0; i <= k; ++i) {
//            for(int j = 0; j <= p; ++j) printf("%lld ", mp[i][j]);
//            printf("\n");
//        }
        for(int i = 1; i <= p; ++i) {
            for(int j = 1; j <= k; ++j) sum[j] = mp[j][i];
            build(1, k, 1);
            ans = big(ans, all[1]);
            for(int j = i + 1; j <= p; ++j) {
                for(int h = 0; h < vs[j].size(); ++h) update(vs[j][h].fi, vs[j][h].se, 1, k, 1);
                ans = big(ans, all[1]);
            }
        }
        for(int i = 0; i <= k; ++i) for(int j = 0; j <= p; ++j) mp[i][j] = 0;
        printf("%lld\n", ans);
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*(clock()-p0)/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}

你可能感兴趣的:(2019杭电/牛客多校待补题和已补题)