• 一道人生哲理题(一步一步优化)


    https://vjudge.net/contest/500589#problem/D

    一开始想拓扑,用了一个multiset维护其子节点对自己的贡献,然后每次将他的set遍历一遍,然后就,再决定他用不用加一下。

    因为贪心所以尽量加到r[x],因为贪心,把当前点加到l[x],即可,因为他对父亲的贡献不是有自己决定的,有父亲节点决定。

    但是TLE,分析,扫multiset的过程其实没必要,这样就是恰好满足r[x],但是用范围就行,

    还是:决定父节点的不在自己,而在于其父亲。

    所以只用知道儿子贡献总和的上限就行了,若大于l[x],不用处理,若小于r[x],贪心来讲加满更优,父节点的上界更大。还得向上传,因为每次只分析两层的状态,将状态向上传。

    超时代码

    点击查看代码
    #include<cstdio>
    #include<algorithm>
    #include<set>
    #include<queue>
    using namespace std;
    const int N=2e5+10;
    typedef long long ll;
    int cnt[N],p[N],n;
    ll a[N],l[N],r[N],ans;
    queue<int> q;
    struct cmp{
    	bool operator()(const ll& a,const ll& b){return a>b;}
    };
    multiset<ll,cmp> bar[N];
    //表示子节点自己积累的
    void init(){
    	ans=0;
    	fill(cnt+1,cnt+1+n,0);
    	fill(a+1,a+1+n,0);
    	for(int i=1;i<=n;++i)if(!bar[i].empty())bar[i].clear();
    }
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d",&n);
    		init();
    		for(int i=2;i<=n;++i)scanf("%d",&p[i]),cnt[p[i]]++;
    		for(int i=1;i<=n;++i)scanf("%lld%lld",&l[i],&r[i]);
    		for(int i=1;i<=n;++i)if(!cnt[i])q.push(i),bar[i].insert(r[i]),ans++;
    		while(!q.empty()){
    			int x=q.front();q.pop();
    			int f=p[x];cnt[f]--;
    			if(!cnt[f])q.push(f);
    			//只要小于r[x]就可以向上传,才会更大。若等于或大于没必要传。
    			//若子节点的都传完了,那么就需要自己加了,这时答案就需要修改
    			if(a[x]<r[x]){
    				while(a[x]<r[x]&&!bar[x].empty()){
    					ll maxn=*bar[x].begin();bar[x].erase(bar[x].begin());
    					ll Cha=r[x]-a[x];
    					if(Cha<=maxn){
    						a[x]=r[x];
    						bar[f].insert(Cha);
    					}else{
    						a[x]+=maxn;
    						bar[f].insert(maxn);
    					}
    				}
    				if(a[x]<l[x]){
    					ans++;
    					bar[f].insert(r[x]-a[x]);
    					a[x]=r[x];
    				}		
    			}
    		}
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    

    AC代码

    点击查看代码
    #include<cstdio>
    #include<algorithm>
    #include<set>
    #include<queue>
    using namespace std;
    const int N=2e5+10;
    typedef long long ll;
    int cnt[N],p[N],n;
    ll a[N],l[N],r[N],ans;
    queue<int> q;
    void init(){
    	ans=0;
    	fill(cnt+1,cnt+1+n,0);
    	fill(a+1,a+1+n,0);
    }
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d",&n);
    		init();
    		for(int i=2;i<=n;++i)scanf("%d",&p[i]),cnt[p[i]]++;
    		for(int i=1;i<=n;++i)scanf("%lld%lld",&l[i],&r[i]);
    		for(int i=1;i<=n;++i)if(!cnt[i])q.push(i);
    		while(!q.empty()){
    			int x=q.front();q.pop();
    			int f=p[x];cnt[f]--;
    			if(!cnt[f])q.push(f);
    			if(a[x]<l[x])ans++,a[x]=r[x];
    			if(a[x]>r[x])a[x]=r[x];
    			a[f]+=a[x];
    		}
    		printf("%lld\n",ans);
    	}
    	//只要小于r[x]就可以向上传,才会更大。若等于或大于没必要传。
    	//若子节点的都传完了,那么就需要自己加了,这时答案就需要修改
    	//害。。。用什么multiset啊,用一个数组表示表示一下不就得了。
    	return 0;
    }
    
  • 相关阅读:
    DHCP分配ip地址。0.0.0.0与255.255.255.255
    net-snmp配置文件详解
    net-snmp开发中出现“Error opening specified endpoint"" ”的解决方案
    Elasticsearch 学习笔记
    Prometheus 监控报警系统 AlertManager 之邮件告警
    Match All Query
    Elasticsearch postman
    Centos7修改root密码
    ElasticSearch中profile API的使用
    kafka查询某时间段内的消息
  • 原文地址:https://www.cnblogs.com/zasdcn/p/16401466.html
Copyright © 2020-2023  润新知