zoukankan      html  css  js  c++  java
  • P5298 [PKUWC2018]Minimax

    题目链接

    都到 NOI 了还不会整体 DP,所以特意学了一下。

    首先我们能够轻易地想到 (n^2) DP 的做法:设 (f(p,w)) 表示点 (p) 的值为 (w) 的概率。转移:

    [Q_p = 1 - P_p ]

    [lsum(p,w) = sum_{i le w}f(p,i) ]

    [rsum(p,w)=sum_{i ge w}f(p,i) ]

    [f(p,w) gets f(rs,w)(P_plsum(ls,w) + Q_prsum(ls,w)) ]

    [f(p,w) gets f(ls, w)(P_plsum(rs,w) + Q_prsum(rs,w)) ]

    限制枚举范围可以优化到 (O(sum dep_p)),能通过 50pts

    然后发现这个转移有共性,相当于系统地给 dp 值做一种操作。我们可以用线段树来模拟。不过这个题并不是整体DP的板子题,它有很多方便的地方,比如说我们可以拆分贡献,转化为左对右/右对左的贡献,直接转化成区间乘问题。因此我们对 (x,y) 分别记个左右的前/后缀和,到只有一个有点的时候直接打乘法标记即可。由于空节点的权值都是零,打乘法标记也没用,因此不用管如何将标记传给“空儿子”。

    复杂度:(O(nlogn))

    关键代码:

    inline void pushtag(int cur, ll v) {
    	if (!cur)	return ;
    	sum[cur] = sum[cur] * v % P;
    	tag[cur] = tag[cur] * v % P;
    }
    inline void pushdown(int cur) {
    	if (tag[cur] != 1)
    		pushtag(ls[cur], tag[cur]), pushtag(rs[cur], tag[cur]), tag[cur] = 1;
    }
    void add(int L, int R, int pos, int &cur) {
    	if (!cur)	cur = ++ttot, tag[cur] = 1;
    	++sum[cur];
    	if (L == R)	return ;
    	int mid = (L + R) >> 1;
    	if (pos <= mid)	add(L, mid, pos, ls[cur]);
    	else	add(mid + 1, R, pos, rs[cur]);
    }
    int merge(ll lx, ll rx, ll ly, ll ry, ll p, ll q, int x, int y) {
    	if (!x && !y)	return 0;//Attention!!!!! &&
    	pushdown(x), pushdown(y);//Attention!!!!
    	if (!x) {
    		pushtag(y, (p * lx % P + q * rx % P) % P);
    		return y;
    	}
    	if (!y) {
    		pushtag(x, (p * ly % P + q * ry % P) % P);
    		return x;
    	}
    	ll nlx = lx + sum[ls[x]], nrx = rx + sum[rs[x]];
    	ll nly = ly + sum[ls[y]], nry = ry + sum[rs[y]];
    	nlx %= P; nrx %= P; nly %= P; nry %= P;//Attention!!!!!!
    	ls[x] = merge(lx, nrx, ly, nry, p, q, ls[x], ls[y]);
    	rs[x] = merge(nlx, rx, nly, ry, p, q, rs[x], rs[y]);
    	sum[x] = (sum[ls[x]] + sum[rs[x]]) % P;//Attention!!!!
    	return x;
    }
    void dfs(int cur) {
    	int sz = son[cur].size();
    	if (!sz) {
    		add(1, htot, v[cur], rt[cur]);
    	} else if (sz == 1) {
    		dfs(son[cur][0]);
    		rt[cur] = rt[son[cur][0]];
    	} else {
    		dfs(son[cur][0]), dfs(son[cur][1]);
    		rt[cur] = merge(0, 0, 0, 0, p[cur], q[cur], rt[son[cur][0]], rt[son[cur][1]]);
    	}
    }
    
  • 相关阅读:
    自定义TabControl
    认识——转化的力量
    提取网页中的javascript脚本和下载链接
    【作业】简单绘图程序
    遥感中几个物理量计算及比较
    [C++学习]C++内存管理
    小技巧
    Threading.Timer学习
    Unsupported Oracle data type 101 encountered
    Vs2008不能调试的问题
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13532057.html
Copyright © 2011-2022 走看看