zoukankan      html  css  js  c++  java
  • [NOIP2018]赛道修建

    嘟嘟嘟


    因为一些知道的人所知道的,不知道的人所不知道的原因,我来写今年的NOIP了。
    现在看这题,心中满是疑问:我当时是多么的zz,这种水题为啥没做出来……


    不管了,说正事。
    先考虑部分分。
    1.(n leqslant 15)
    不会。
    2.(m = 1)
    带权树的直径啊。树形dp一下维护最长链次长链即可。
    3.菊花图。
    最长的一组路径显然可能是由一条边或是任意两条边组成。
    (m <= frac{n - 1}{2})的时候,贪心把前(2m)大的边最大的匹配最小的即可。
    否则把最大的一些单独拎出来,剩下的两两匹配就完事了。
    答案就是所有的max。
    然后我考场上把这个写跪了……原因是第一种情况直接最大的匹配最小的,那中间的给扔了。(怒丢20分)
    4.链
    普及二分题。


    这就是大众分55分啦。


    至于二叉树咋回事,可以说是标程的弱化版。
    也是二分,然后判断能否选出大于等于mid的m条路来。
    然后对于每一个结点,分情况讨论:
    1.如果左子树的链加边权大于等于mid,断掉作为一条新赛道。
    2.右子树同理。
    3.如果其中一棵子树的链加上边权比mid小,就贪心的把更长的链接到这个节点上,用来往上延伸。
    没啦。


    那么标程就很显然了。
    对于结点(u),能在子树内匹配的就在子树内匹配,否则找一条最长的链延伸上去。
    实现的时候每一层用一个multiset或vector+sort都行。


    然后luogu卡vector(loj上过了),非得换成multiset。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 5e4 + 5;
    inline ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), last = ' ';
    	while(!isdigit(ch)) last = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(last == '-') ans = -ans;
    	return ans;
    }
    inline void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, m;
    struct Edge
    {
    	int nxt, to, w;
    }e[maxn << 1];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y, int w)
    {
    	e[++ecnt] = (Edge){head[x], y, w};
    	head[x] = ecnt;
    }
    
    int a[maxn];
    In void work0()		//菊花图 
    {
    	--n;
    	for(int i = 0, j = 1; i <= ecnt; i += 2, ++j) a[j] = e[i].w;
    	sort(a + 1, a + n + 1);
    	if(m <= (n >> 1))
    	{
    		int L = n - (m << 1) + 1;
    		int Min = INF;
    		for(int i = L, j = 1; j <= m; ++i, ++j) Min = min(Min, a[i] + a[n - j + 1]);
    		write(Min), enter;
    	}
    	else
    	{
    		int tp = n - m, Min = INF;
    		for(int i = 1; i <= tp; ++i) Min = min(Min, a[i] + a[(tp << 1) - i + 1]);
    		Min = min(Min, a[(tp << 1) + 1]);
    		write(Min), enter;
    	}	
    }
    
    In void dfs1(int now, int _f, int stp)
    {
    	for(int i = head[now], v; i != -1; i = e[i].nxt)
    		if((v = e[i].to) ^ _f) a[stp] = e[i].w, dfs1(v, now, stp + 1);
    }
    In bool judge1(ll x)
    {
    	int cnt = 0;
    	for(int i = 1, sum = 0; i < n; ++i) 
    	{
    		if(sum + a[i] >= x) ++cnt, sum = 0;
    		else sum += a[i];
    	}
    	return cnt >= m;
    }
    In void work1()		//链 
    {
    	dfs1(1, 0, 1);		
    	ll L = 0, R = (ll)5e9;
    	while(L < R)
    	{
    		ll mid = (L + R) >> 1;
    		if(judge1(mid))
    		{
    			if(L == mid) break;
    			L = mid;
    		}
    		else 
    		{
    			if(R == mid - 1) break;
    			R = mid - 1;
    		}
    	}
    	write(L), enter;
    }
    
    ll dp[maxn], ans = 0;
    In void dfs2(int now, int _f)
    {
    	ll Max1 = 0, Max2 = 0;
    	for(int i = head[now], v; i != -1; i = e[i].nxt)
    	{
    		if((v = e[i].to) == _f) continue;
    		dfs2(v, now);
    		if(dp[v] + e[i].w > Max1) Max2 = Max1, Max1 = dp[v] + e[i].w;
    		else if(dp[v] + e[i].w > Max2) Max2 = dp[v] + e[i].w;
    	}
    	ans = max(ans, Max1 + Max2);
    	dp[now] = Max1;
    }
    
    In void work2()		//m = 1
    {
    	dfs2(1, 0);
    	write(ans), enter;
    }
    
    int cnt = 0;
    multiset<ll>::iterator pos;
    
    multiset<ll> val[maxn];
    In void dfs(int now, int _f, ll x)
    {
    	for(int i = head[now], v; i != -1; i = e[i].nxt)
    	{
    		if((v = e[i].to) == _f) continue;
    		dfs(v, now, x);
    		dp[v] += e[i].w;
    		if(dp[v] >= x) ++cnt;
    		else val[now].insert(dp[v]);
    	}
    	ll Max = 0;
    	while(!val[now].empty())
    	{
    		if(val[now].size() == 1) {Max = max(Max, *val[now].begin()); val[now].erase(val[now].find(*val[now].begin())); break;}
    		pos = val[now].lower_bound(x - *val[now].begin());
    		if(pos == val[now].end())
    		{
    			Max = max(Max, *val[now].begin());
    			val[now].erase(val[now].find(*val[now].begin()));
    		}
    		else
    		{
    			++cnt;
    			val[now].erase(val[now].find(*pos));
    			val[now].erase(val[now].find(*val[now].begin()));
    			
    		}
    	}
    	dp[now] = Max;
    }
    In bool judge(ll x)
    {
    	cnt = 0;
    	dfs(1, 0, x);
    	return cnt >= m;
    }
    
    int main()
    {
    	Mem(head, -1);
    	n = read(), m = read();
    	bool flg0 = 1, flg1 = 1;
    	ll sum = 0;
    	for(int i = 1; i < n; ++i)
    	{
    		int x = read(), y = read(), w = read();
    		addEdge(x, y, w); addEdge(y, x, w);
    		if(x ^ 1) flg0 = 0;
    		if(y != x + 1) flg1 = 0;	
    		sum += w;
    	}
    	if(flg0) {work0(); return 0;}
    	if(flg1) {work1(); return 0;}
    	if(m == 1) {work2(); return 0;}
    	ll L = 0, R = sum;
    	while(L < R)
    	{
    		ll mid = (L + R + 1) >> 1;
    		if(judge(mid)) L = mid;
    		else R = mid - 1;
    	}
    	write(L), enter;
    	return 0;
    }
    
  • 相关阅读:
    Linux新用户创建与删除细节详解
    通过windows远程访问linux桌面的方法(简单)
    物理机网络地址配置原理
    Hive安装中metadata初始化问题
    彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
    基于react+react-router+redux+socket.io+koa开发一个聊天室
    深入探析koa之异步回调处理篇
    深入探析koa之中间件流程控制篇
    【踩坑记录】一个新手几乎都踩过的坑...
    NodeJS优缺点及适用场景讨论
  • 原文地址:https://www.cnblogs.com/mrclr/p/10344182.html
Copyright © 2011-2022 走看看