zoukankan      html  css  js  c++  java
  • GMOJ 6851. 【2020.11.04提高组模拟】数据恢复

    题目大意

    题解

    这题考场想了很久,但还是没有做出来。

    正解也不难想,容易发现对于每一个点,紧接在这个点后面的点肯定是他的儿子节点。

    然后类比菊花图的情况,不难发现将这个点后面(b_i/a_i)最大的点接在后面是最优的。

    于是做法就出来了,用堆维护(b_i/a_i)的值,每次找出最大的,将这个点接在他父亲的后面,然后将这两个点合并成一个点。

    问题就只剩下合并后的点的权值了,用类似的方法化简一下式子,可以发现如果有一个点(z)要排在(x)(y)合并成的点前面,必然有:

    [frac{b_z}{a_z}>frac{b_x+b_y}{a_x+a_y} ]

    所以可以发现,两个合并后的a,b值就是两个点的a,b值之和。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 500000
    #define ll long long
    using namespace std;
    int n,fa[N],i,num,heap[N],next[N],np[N],x,tot,fap[N],fax,sonx,id[N];
    ll ans,sum;
    struct node{
    	ll a,b;
    }fp[N],gp[N];
    int cmp(int x,int y){
    	return fp[x].b*fp[y].a>fp[x].a*fp[y].b;
    }
    void work(int x){
    	int tp=x,s;
    	while (tp>=1&&cmp(heap[tp],heap[tp/2])){
    		swap(heap[tp],heap[tp/2]);
    		id[heap[tp]]=tp;id[heap[tp/2]]=tp/2;
    		tp/=2;
    	}
    	while ((tp*2<=num)&&(cmp(heap[tp],heap[tp*2])==0||(tp*2+1<=num&&cmp(heap[tp],heap[tp*2+1])==0))){
    		if (tp*2+1>num||cmp(heap[tp*2],heap[tp*2+1])) s=tp*2;
    		else s=tp*2+1;
    		swap(heap[tp],heap[s]);
    		id[heap[tp]]=tp;id[heap[s]]=s;
    		tp=s;
    	}
    }
    void insert(int x){
    	heap[++num]=x;
    	id[x]=num;
    	work(num);
    }
    void delet(){
    	heap[1]=heap[num];
    	num--;
    	work(1);
    }
    int getson(int x){
    	if (np[x]==x) return x;
    	np[x]=getson(np[x]);
    	return np[x];
    }
    int getfa(int x){
    	if (fap[x]==x) return x;
    	fap[x]=getfa(fap[x]);
    	return fap[x];
    }
    int main(){
    	freopen("data.in","r",stdin);
    	freopen("data.out","w",stdout);
    	scanf("%d",&n);
    	for (i=2;i<=n;i++) scanf("%d",&fa[i]),fap[i]=fa[i];
    	for (i=1;i<=n;i++) scanf("%lld%lld",&fp[i].a,&fp[i].b),insert(i),np[i]=fap[i]=i,gp[i]=fp[i];
    	for (i=1;i<=n;i++){
    		x=heap[1];
    		delet();
    		if (x!=1){
    			sonx=getson(fa[x]);
    			next[sonx]=x;
    			np[sonx]=x;
    			
    			fap[x]=sonx;
    			fax=getfa(x);
    			fp[fax].a+=fp[x].a;
    			fp[fax].b+=fp[x].b;
    			work(id[fax]);
    		}
    	}
    	i=next[1];
    	sum=gp[1].b;
    	while (i){
    		ans+=gp[i].a*sum;
    		sum+=gp[i].b;
    		i=next[i];
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    关于使用cocoaPods,import导入时第三方库头文件没有提示问题的解决办法
    在iOS项目中,这样才能完美的修改项目名称
    Mac OS删除文件夹和文件的命令
    mac添加环境变量
    gdb教程
    判断链表是否有环和两个单链表是否相交
    C/C++ 获取文件大小
    exit()与_exit()的区别
    atoi 和 itoa的实现
    new和malloc的区别
  • 原文地址:https://www.cnblogs.com/Mohogany/p/13934216.html
Copyright © 2011-2022 走看看