ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-09-22 21:04:35  阅读:136  来源: 互联网

标签:__ p2 3780 p1 int Luogu ++ SDOI2017 dp


首先一个很聚的转化是把\(t - h \leq k\)转化为先在一条链上不带代价地选择一个, 然后有代价地进行一堆树的dp。
根据贪心的性质, 这个链肯定到底。然后你再去搞出度的dfs序, 也就是出来的时候记录一个点。那么树dp可以转化到这个序列上的一个dp。
具体来说, 转移是\(dp_{i, j} = \max \{dp_{i - sz_i, j}, dp_{i - 1, j - t} + vi \times 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 != '\n' && ch != ' ') return *this;
			}
		}
		inline Input& operator >>(char *s) {
			int p = 0;
			while(1) {
				s[p] = gc();
				if(s[p] == '\n' || s[p] == ' ' || s[p] == EOF) break;
				p ++; 
			}
			s[p] = '\0';
			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 != '\0' ) pc(* p ++);
			return * this;
		}
		~Output() { flush(); } 
	#undef MX
} Fout;

#define cin Fin
#define cout Fout
#define endl '\n'

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;
}

标签:__,p2,3780,p1,int,Luogu,++,SDOI2017,dp
来源: https://www.cnblogs.com/clover4/p/15321620.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有