• bzoj4458: GTY的OJ


    题目大意:给定一棵带点权的有根树,同时给定L,R,要求找M条链,每条链满足以下条件的情况下,要求所有链权和最大:

    1、两两不相同(可以包含/相交等)

    2、节点数在[L,R]间

    3、其中一个端点的深度必须是整条链所有点深度的最小值(原谅我实在不会表达……)(形象地说,就是直上直下)


    感觉和NOI某原题什么钢琴有点像

    当一条链的下端点确定时,上端点的选择范围就是一条链,也就是说,我们可以求出每个点到根的点权和val[u]存入主席树,这样就可以求 以指定点为下端点 权第k大的链了。

    用堆来维护 所有下端点当前权最大的链,每取出一个当前最大值,假设它是其下端点权第k大的链,就在主席树里找这个下端点权第k+1大的链

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #define ll long long
    #define N 500005
    #define M 500005
    #define INF (1e9)
    
    using namespace std;
    inline int read(){
    	int ret=0;char ch=getchar();
    	bool flag=0;
    	while (ch<'0'||ch>'9'){
    		flag=ch=='-';
    		ch=getchar();
    	}
    	while ('0'<=ch&&ch<='9'){
    		ret=ret*10-48+ch;
    		ch=getchar();
    	}
    	return flag?-ret:ret;
    }
    
    int n;
    int fa[N],f[N][22],fl[N],fr[N],deep[N];
    int a[N],val[N];
    int need,L,R;
    int root[N];
    
    void init(){
    	n=read()+1;fa[2]=read()+1;
    	for (int i=3;i<=n;++i) fa[i]=read()+1;
    	for (int i=2;i<=n;++i) a[i]=read();
    	fa[1]=a[1]=0;
    	need=read();L=read();R=read()+1;//interval->[L,R)
    }
    
    struct SegmentTree{
    	struct STnode{
    		int sum,ls,rs;
    	} t[N*33];
    	int size;
    	void clear(){size=t[0].sum=t[0].ls=t[0].rs=0;}
    	void modify(int &x,int L,int R,int pos){
    		t[++size]=t[x];
    		x=size;
    		++t[x].sum;
    		if (L==R) return;
    		int mid=(L+R)/2;
    		if (L+R<0) --mid;
    		if (pos<=mid) modify(t[x].ls,L,mid,pos);
    		else modify(t[x].rs,mid+1,R,pos);
    	}
    	int qmink(int x,int y,int L,int R,int k){
    		if (L==R) return L;
    		int tmp=t[t[x].ls].sum-t[t[y].ls].sum,mid=(L+R)/2;
    		if (L+R<0) --mid;
    		if (k<=tmp) return qmink(t[x].ls,t[y].ls,L,mid,k);
    		else return qmink(t[x].rs,t[y].rs,mid+1,R,k-tmp);
    	}
    } st;
    
    void precompute(){
    	val[0]=a[0]=deep[0]=fa[0]=0;
    	for (int i=1;i<=n;++i){
    		val[i]=val[fa[i]]+a[i];
    		deep[i]=deep[fa[i]]+1;
    		f[i][0]=fa[i];
    	}
    	memset(f[0],0,sizeof(f[0]));
    	for (int k=1;k<=20;++k)
    		for (int i=1;i<=n;++i)
    			f[i][k]=f[f[i][k-1]][k-1];
    	
    	st.clear();root[0]=0;
    	for (int i=1;i<=n;++i){
    		fl[i]=fr[i]=i;
    		for (int k=0;k<=20;++k){
    			if ((L&(1<<k))>0) fl[i]=f[fl[i]][k];
    			if ((R&(1<<k))>0) fr[i]=f[fr[i]][k];
    		}
    		
    		st.modify(root[i]=root[fa[i]],-INF,INF,val[i]);
    	}
    }
    
    struct HeapNode{
    	int pos,value,k;
    	HeapNode(){}
    	HeapNode(int _pos,int _value,int _k):pos(_pos),value(_value),k(_k){}
    };
    inline bool operator <(const HeapNode &u,const HeapNode &v){
    	return u.value<v.value;
    }
    priority_queue<HeapNode> h;
    
    void work(){
    	while (!h.empty()) h.pop();
    	for (int i=1;i<=n;++i)
    		if (deep[fl[i]]-deep[fr[i]])
    			h.push(HeapNode(i,val[i]-st.qmink(root[fl[i]],root[fr[i]],-INF,INF,1),1));
    	ll ans=0;
    	while (need--){
    		HeapNode now=h.top();
    		h.pop();
    		ans+=(ll)now.value;
    		int u=fl[now.pos],v=fr[now.pos];
    		if (deep[u]-deep[v]>now.k)
    			h.push(HeapNode(now.pos,val[now.pos]-st.qmink(root[u],root[v],-INF,INF,now.k+1),now.k+1));
    	}
    	printf("%lld
    ",ans);
    }
    
    int main(){
    	init();
    	precompute();
    	work();
    	return 0;
    }
    

      

  • 相关阅读:
    Zookeeper 记录
    Eureka 分析记录
    Hbase 学习记录
    小技巧 Mongodb 动态查询 除去 _class 条件
    科技的继续发展会带给我们什么?
    无限拓展热区域缓存服务方案
    Git 的 4 个阶段的撤销更改
    自动化运维利器 Fabric
    Linux Shell 文本处理工具
    如何在 Linux 中找出 CPU 占用高的进程
  • 原文地址:https://www.cnblogs.com/wangyurzee7/p/5349831.html
Copyright © 2020-2023  润新知