• loj3166. 「CEOI2019」魔法树


    题面

    题意:自已去看

    题解:首先考虑dp。设(dp_{i,j})表示(i)的子树内,总时间为(j)时的最大收益。转移是显然的,能对其造成贡献的是每一个儿子(v)(dp_{v,k}(k leq j))。然后再加上自己的贡献即可。

    优化1:发现有用的时间只有(n)种,所以可以将时间离散化。时间复杂度是(O(n^2))的。

    优化2:我们先不考虑当前节点的贡献。发现两个儿子直接合并的复杂度是(O(n))的,考虑优化。发现对于每个(i)和其子树内出现过的(j)(dp_{i,j})一定是递增的,因为(dp_{i,j}=max(dp_{i,j},dp_{i,j-1}))。所以如果我们用map记录(dp)数组,并将(dp)数组差分,那么就能做到启发式合并了。直接合并两个map即可。

    最后考虑当前节点的果实的贡献。设当前节点果实成熟的时间为(t),那么(dp_{i,t}+=w_i),然后考虑有一些(dp_{i,j}(j>t))会比(dp_i,t)小,那么找到这些小的,把它们从map里删除就行了。

    时间复杂度:(O(nlog^2n))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    vector<int>e[101000],vec[101000];
    map<int,ll>s[101000];
    int n,m,k,fa[101000],root[101000],t[101000];
    ll w[101000];
    ll ans,sum;
    inline bool bbb(int x,int y){return t[x]==t[y]?w[x]<w[y]:t[x]<t[y];}
    I D_1(int x){
    	for(auto d:e[x]){
    		D_1(d);
    		if(s[x].size()<s[d].size())swap(s[x],s[d]);
    		for(auto it=s[d].begin();it!=s[d].end();it++){
    			s[x][it->first]+=it->second;
    		}
    		s[d].clear();
    	}
    	sort(vec[x].begin(),vec[x].end(),bbb);
    	for(auto d:vec[x]){
    		s[x][t[d]]+=w[d];register ll dt=w[d];
    		for(auto it=s[x].upper_bound(t[d]),tmp=it;it!=s[x].end();){
    			if(dt>=it->second){dt-=it->second;tmp=it++,s[x].erase(tmp);}
    			else{it->second-=dt;break;}
    		}
    	}
    }
    int main(){
    	read(n);read(m);read(k);
    	F(i,2,n)read(fa[i]),e[fa[i]].emplace_back(i);
    	re X;
    	F(i,1,m){
    		read(X);vec[X].emplace_back(i);
    		read(t[i]);read(w[i]);
    	}
    	D_1(1);
    	for(auto it=s[1].begin();it!=s[1].end();it++){
    		sum+=it->second;
    	}
    	printf("%lld",sum);
    	return 0;
    }
    /*
    6 4 10
    1
    2
    1
    4
    4
    3 4 5
    4 7 2
    5 4 1
    6 9 3
    */
    
    
  • 相关阅读:
    IE6下实现Width:auto
    Dynamic Linq 的Like扩展
    用一句JQuery代码实现表格的简单筛选
    jquery:利用jsonp跨域访问转载
    LINQ动态组合查询
    Windows服务中Timer组件
    正则表达式笔记转载
    继LINQ动态组合查询PredicateExtensions讲解
    错误笔记:在OleDb执行下Access ,程序不报错,但是Update也更新不成功的
    jQuery 1.4 版本的十五个新特性转载
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/13308283.html
Copyright © 2020-2023  润新知