zoukankan      html  css  js  c++  java
  • 树上最小权覆盖(可并堆)

    题目大意

      以(1)为根,(n)个点的树,给(m)条直上直下的链,每个链有权值,求最小权覆盖。

    解题思路

      曾经猫老师讲过的一道题。首先考虑序列上的最小权区间覆盖,一个人尽皆知的方法是数据结构优化(dp)做,但还有一种方法是用堆。堆里存二元组((a,b))表示花费(a)使得([1,b])被覆盖,这个以(a)为关键字,然后按照左端点排序,每次取出(b)([l,r])内的最小值,然后更新答案。尝试把这个做法扩展到树上,发现需要进行合并,那么就可以可并堆了,时间复杂度(O(nlogn))

    代码

    #pragma GCC optimize("inline","Ofast")
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    
    using namespace std;
    const int N=1000005;
    
    inline int rd(){
    	int x=0,f=1; char ch=getchar();
    	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    
    int n,m,fa[N],dep[N],rt[N],dis[N],ch[N][2],top[N],val[N],tot,tag[N];
    vector<pair<int,int> > v[N];
    vector<int> G[N];
    
    void pushdown(int x){
    	if(tag[x]){
    		val[x]+=tag[x];
    		tag[ch[x][0]]+=tag[x];
    		tag[ch[x][1]]+=tag[x];
    		tag[x]=0;
    	}
    }
    
    int merge(int x,int y){
    	if(!x || !y) return (x|y);
    	pushdown(x); pushdown(y);
    	if(val[x]>val[y]) swap(x,y);
    	ch[x][1]=merge(ch[x][1],y);
    	if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    	dis[x]=dis[ch[x][1]]+1; 
    	return x;
    }
    
    void DFS(int x){
    	for(int i=0;i<v[x].size();i++){
    		val[++tot]=(v[x][i]).first;
    		top[tot]=(v[x][i]).second;
    		rt[x]=merge(rt[x],tot);
    	}
    	int sum=0,w;
    	for(int i=0;i<G[x].size();i++){
    		DFS(G[x][i]); pushdown(rt[G[x][i]]); 
    		w=val[rt[G[x][i]]]; tag[rt[x]]+=w; 
    		tag[rt[G[x][i]]]+=sum; sum+=w;
    		rt[x]=merge(rt[x],rt[G[x][i]]);
    	}
    	while(rt[x]){
    		pushdown(rt[x]);
    		if(dep[top[rt[x]]]>dep[x]) rt[x]=merge(ch[rt[x]][0],ch[rt[x]][1]);
    		else break;
    	}
    	if(!rt[x]) {puts("-1"); exit(0);}
    }
    
    int main(){
    	dep[1]=1;
    	n=rd(),m=rd(); int x,y,z;
    	for(int i=2;i<=n;i++){
    		fa[i]=rd(); dep[i]=dep[fa[i]]+1;
    		G[fa[i]].push_back(i);
    	}
    	for(int i=1;i<=m;i++){
    		x=rd(),y=rd(),z=rd();
    		v[y].push_back(make_pair(z,x));
    	}
    	DFS(1); printf("%d
    ",val[rt[1]]);
    	return 0;
    }
    
  • 相关阅读:
    基于node.js+socket.io+html5实现的斗地主游戏(1)概述
    [javascript]switchTab:仿腾讯首页Tab栏切换js插件
    [js]利用闭包向post回调函数传参数
    [CSS]利用伪元素实现一些特殊图形 from baidu校招
    [javascript]模块化&命名污染—from 编程精解
    [随手记]2014前端面试题解
    [IE bug] ajax请求 304解决方案
    [java]基于UDP的Socket通信Demo
    [JQuery]ScrollMe滚动特效插件
    java.lang.OutOfMemoryError及解决方案
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10561176.html
Copyright © 2011-2022 走看看