• [做题记录-乱做]Luogu 3780 [SDOI2017]苹果树


    首先一个很聚的转化是把(t - h leq k)转化为先在一条链上不带代价地选择一个, 然后有代价地进行一堆树的dp。
    根据贪心的性质, 这个链肯定到底。然后你再去搞出度的dfs序, 也就是出来的时候记录一个点。那么树dp可以转化到这个序列上的一个dp。
    具体来说, 转移是(dp_{i, j} = max {dp_{i - sz_i, j}, dp_{i - 1, j - t} + vi imes t })
    然后你发现如果这样搞, 把一个点拆成两个, 一个用来当链, 贡献一个, 一个用来贡献剩下的, 然后把用来贡献的那个点的爸爸设置为原来那个点。发现把边表反过来和正着跑可以恰好构成贡献。那么单调队列优化一下dp然后正反拼拼贡献即可。

    /*
    	QiuQiu /qq
      ____    _           _                 __                
      / __   (_)         | |               / /                
     | |  | |  _   _   _  | |  _   _       / /    __ _    __ _ 
     | |  | | | | | | | | | | | | | |     / /    / _` |  / _` |
     | |__| | | | | |_| | | | | |_| |    / /    | (_| | | (_| |
      \___\_ |_|  \__,_| |_|  \__, |   /_/      \__, |  \__, |
                                __/ |               | |     | |
                               |___/                |_|     |_|
    */
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    class Input {
    	#define MX 1000000
    	private :
    		char buf[MX], *p1 = buf, *p2 = buf;
    		inline char gc() {
    			if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
    			return p1 == p2 ? EOF : *(p1 ++);
    		}
    	public :
    		Input() {
    			#ifdef Open_File
    				freopen("a.in", "r", stdin);
    				freopen("a.out", "w", stdout);
    			#endif
    		}
    		template <typename T>
    		inline Input& operator >>(T &x) {
    			x = 0; int f = 1; char a = gc();
    			for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
    			for(; isdigit(a); a = gc()) 
    				x = x * 10 + a - '0';
    			x *= f;
    			return *this;
    		}
    		inline Input& operator >>(char &ch) {
    			while(1) {
    				ch = gc();
    				if(ch != '
    ' && ch != ' ') return *this;
    			}
    		}
    		inline Input& operator >>(char *s) {
    			int p = 0;
    			while(1) {
    				s[p] = gc();
    				if(s[p] == '
    ' || s[p] == ' ' || s[p] == EOF) break;
    				p ++; 
    			}
    			s[p] = '';
    			return *this;
    		}
    	#undef MX
    } Fin;
    
    class Output {
    	#define MX 1000000
    	private :
    		char ouf[MX], *p1 = ouf, *p2 = ouf;
    		char Of[105], *o1 = Of, *o2 = Of;
    		void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
    		inline void pc(char ch) {
    			* (p2 ++) = ch;
    			if(p2 == p1 + MX) flush();
    		}
    	public :
    		template <typename T> 
    		inline Output& operator << (T n) {
    			if(n < 0) pc('-'), n = -n;
    			if(n == 0) pc('0');
    			while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
    			while(o1 != o2) pc(* (--o1));
    			return *this; 
    		}
    		inline Output & operator << (char ch) {
    			pc(ch); return *this; 
    		}
    		inline Output & operator <<(const char *ch) {
    			const char *p = ch;
    			while( *p != '' ) pc(* p ++);
    			return * this;
    		}
    		~Output() { flush(); } 
    	#undef MX
    } Fout;
    
    #define cin Fin
    #define cout Fout
    #define endl '
    '
    
    using LL = long long;
    
    const int N = 4e4 + 5;
    const int K = 5e5 + 5;
    const int NK = 25000000 + 5;
    
    vector<int> e[N];
    int n, k, fa[N], a[N], v[N], sz;
    vector<int> dp1[N];
    vector<int> dp2[N];
    int ListVal[N];
    
    int dfn1[N], dfn2[N], siz[N], loc1[N], loc2[N], dep[N];
    
    void clr() {
    	for(int i = 1; i <= sz; i ++) e[i].clear();
    	for(int i = 0; i <= sz; i ++) {
    		vector<int> a, b;
    		dp1[i].swap(a), dp2[i].swap(b);
    	}
    	dfn1[0] = dfn2[0] = 0;
    }
    
    void dfs1(int x, int fx = 0) {
    	siz[x] = 1; dep[x] = dep[fx] + 1;
    	ListVal[x] = ListVal[fa[x]] + v[x];
    	for(int y : e[x]) dfs1(y, x), siz[x] += siz[y];
    	dfn1[x] = ++ dfn1[0];
    	loc1[dfn1[0]] = x;
    }
    
    void dfs2(int x) {
    	for(int y : e[x]) dfs2(y);
    	dfn2[x] = ++ dfn2[0];
    	loc2[dfn2[0]] = x;
    }
    
    inline int max(int x, int y) { return x > y ? x : y; }
    
    inline void dapai(vector<int> *dp, int *dfn, int *loc) {
    //	for(int i = 0; i <= sz; i ++)
    //		for(int j = 0; j <= k; j ++) dp[i][j] = 0;
    	for(int i = 1; i <= sz; i ++) {
    		int x = loc[i];
    		for(int j = 0; j <= k; j ++) {
    			dp[i][j] = dp[i - siz[x]][j];
    		}
    		static int q[K];
    		register int l = 1, r = 0;
    	//	deque<int> q; q.push_back(0);
    		q[++ r] = 0;
    		dp[i][0] = 0;
    		for(register int j = 1; j <= k; j ++) {
    			while(l <= r && j - q[l] > a[x]) l ++;
    			//if(l <= r) 
    			dp[i][j] = max(dp[i][j], dp[i - 1][q[l]] + v[x] * (j - q[l]));
    			while(l <= r && dp[i - 1][j] > dp[i - 1][q[r]] + (j - q[r]) * v[x]) r --;
    			q[++ r] = j;
    		}
    	}
    }
    
    void solve() {
    	cin >> n >> k;
    	for(int i = 1; i <= n; i ++) {
    		cin >> fa[i] >> a[i] >> v[i];
    	}
    	sz = n;
    	static int vis[N];
    	memset(vis, 0, sizeof(vis));
    	for(int i = 1; i <= n; i ++) {
    		if(fa[i]) 
    			e[fa[i]].push_back(i);
    		vis[fa[i]] = 1;
    		if(a[i] > 1) {
    			sz ++;
    			a[sz] = a[i] - 1;
    			v[sz] = v[i];
    			a[i] = 1;
    			e[i].push_back(sz);
    			fa[sz] = fa[i];
    		}
    	}
    	dfs1(1); 
    	for(int i = 1; i <= sz; i ++) reverse(e[i].begin(), e[i].end());
    	dfs2(1);
    	for(int i = 0; i <= sz; i ++) dp1[i].resize(k + 1);
     	for(int i = 0; i <= sz; i ++) dp2[i].resize(k + 1);
    	dapai(dp1, dfn1, loc1); 
    	dapai(dp2, dfn2, loc2);
    	int ans = 0;
    	for(int i = 1; i <= n; i ++) if(vis[i] == 0) {
    		for(int j = 0; j <= k; j ++) {
    			ans = max(ans, ListVal[i] + dp1[dfn1[i] - 1][j] + dp2[dfn2[i] - siz[i]][k - j]);
    		}
    	}
    	cout << ans << endl;
    	clr();
    }
    
    int main() {
    	//freopen("a.in", "r", stdin);
    	int Case; cin >> Case;
    	while(Case --) solve();
    	return 0;
    }
    
  • 相关阅读:
    Java 的 多态和构造方法
    java 的 抽象类、接口
    java 的 封装 、继承
    eclipse的安装和基本使用、面向对象、类和对象
    方法的重载、引用数据类型、 ArrayList集合
    SQL单行函数
    JAVA
    mysql约束
    MYSQL的常用属性
    mysql的索引
  • 原文地址:https://www.cnblogs.com/clover4/p/15321620.html
Copyright © 2020-2023  润新知