zoukankan      html  css  js  c++  java
  • AGC023F

    题目链接:F - 01 on Tree

    题目大意:给定一棵 (n(nleq 2 imes 10^5)) 个点的树,每一个节点上的取值是 ({0,1}),每一次选择一个没有被删除的点删除,并且加入答案序列的末尾,求出最后答案序列的最小的逆序对数。


    题解:如果让逆序对数最少,那么有一个很明显的贪心就是 0 尽量放到序列的前面,所以说我们可以考虑每一个点的贡献和它的父亲合并,用一个堆维护贪心即可,然后在拿一个并查集搞一下联通块就做完了。

    时间复杂度 (O(nlog n))

    代码:

    #include <queue>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int Maxn=200000;
    int n;
    int fa[Maxn+5];
    int head[Maxn+5],arrive[Maxn+5],nxt[Maxn+5],tot;
    void add_edge(int from,int to){
    	arrive[++tot]=to;
    	nxt[tot]=head[from];
    	head[from]=tot;
    }
    int a[Maxn+5];
    int f[Maxn+5];
    struct Value{
    	int id;
    	int cnt_0,cnt_1;
    	Value(int _cnt_0=0,int _cnt_1=0,int _id=0){
    		cnt_0=_cnt_0;
    		cnt_1=_cnt_1;
    		id=_id;
    	}
    	friend Value operator +(Value a,Value b){
    		Value ans;
    		ans.cnt_0=a.cnt_0+b.cnt_0;
    		ans.cnt_1=a.cnt_1+b.cnt_1;
    		ans.id=a.id;
    		return ans;
    	}
    	Value operator +=(Value b){
    		(*this)=(*this)+b;
    		return (*this);
    	}
    	friend bool operator <(Value a,Value b){
    		return 1ll*a.cnt_0*b.cnt_1<1ll*a.cnt_1*b.cnt_0;
    	}
    	friend bool operator >(Value a,Value b){
    		return 1ll*a.cnt_0*b.cnt_1>1ll*a.cnt_1*b.cnt_0;
    	}
    	friend bool operator ==(Value a,Value b){
    		return a.cnt_0==b.cnt_0&&a.cnt_1==b.cnt_1&&a.id==b.id;
    	}
    	friend bool operator !=(Value a,Value b){
    		return !(a==b);
    	}
    }val[Maxn+5];
    priority_queue<Value> q;
    int find(int x){
    	if(x==f[x]){
    		return x;
    	}
    	return f[x]=find(f[x]);
    }
    void merge(int x,int y){
    	int fa_x=find(x),fa_y=find(y);
    	if(fa_x==fa_y){
    		return;
    	}
    	val[fa_x]+=val[fa_y];
    	f[fa_y]=fa_x;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=2;i<=n;i++){
    		scanf("%d",&fa[i]);
    		add_edge(fa[i],i);
    	}
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<=n;i++){
    		f[i]=i;
    	}
    	for(int i=1;i<=n;i++){
    		if(a[i]==0){
    			val[i]=Value(1,0,i);
    		}
    		else{
    			val[i]=Value(0,1,i);
    		}
    	}
    	for(int i=2;i<=n;i++){
    		q.push(val[i]);
    	}
    	ll ans=0;
    	while(!q.empty()){
    		Value u=q.top();
    		q.pop();
    		if(val[find(u.id)]!=u){
    			continue;
    		}
    		int x=u.id,y=find(fa[x]);
    		ans+=1ll*val[y].cnt_1*val[x].cnt_0;
    		merge(y,x);
    		if(y>1){
    			q.push(val[y]);
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Vue-router路由传参三种方法及区别
    Vue.mixins混入方法的使用
    移动端自适应方案—rem布局
    JS获取页面宽度高度及Vue页面自适应方案
    Vue实现文件的上传与下载
    Prometheus第六篇:prometheus高可用架构
    Prometheus第五篇:prometheus告警规则配置和通过alertmanager精准发送告警
    Prometheus第四篇:prometheus服务发现方式解析
    Prometheus第三篇:prometheus.yml配置解析
    Prometheus第二篇:Prometheus部署
  • 原文地址:https://www.cnblogs.com/withhope/p/14209920.html
Copyright © 2011-2022 走看看