zoukankan      html  css  js  c++  java
  • IOI2021集训队作业129CF Longest Rivers

    给出一棵树,对于每个叶子节点(x),求:在所有的树链剖分方案中,求包含(x)的链的最优排名(长度从大到小排序,排名越靠前越优)。

    (nle 10^6)


    考虑求出一个叶子(x)的答案。首先显然要划分出(rt o x),记这条链的长度为(L)

    定义(len_i)表示从(i)子树中延伸上去的链长(包括(i)到父亲那段),(mx_i)(i)子树中的最长链。

    假如希望(x)能排到rank1,可以如此贪心:做到某个不被链(rt o x)经过的子树(u)时,对于所有(vin son(u)),尝试找到最小的(len_v)并接在边((u,fa_u))下方。如果一直可以满足(len_ule L),那么确实可以排到rank1。在做的过程中,如果出现了一次(len_u>L),那么就让它直接向上延伸到和(rt o x)相交为止。

    整理一下思路,可以发现其实就是求:在(rt o x)以外的子树中,极小的满足(mx_u>L)的子树(u)的个数。另外可以发现对于任意(uin rt o x)(len_ule L),所以都不可能是极小的(u)。所以可以把范围从(rt o x)以外的子树变成所有的子树。

    于是按照询问的叶子深度排序,每次只保留(mx_u>L)的点,此时的叶子个数就是答案。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 1000005
    #define ll long long
    #define INF 1000000000000000
    int n,m;
    char str[N][13];
    struct EDGE{
    	int to,w;
    	EDGE *las;
    } e[N];
    int ne;
    EDGE *last[N];
    int deg[N];
    void link(int u,int v,int w){
    	e[ne]={v,w,last[u]};
    	last[u]=e+ne++;
    	deg[u]++;
    }
    int fa[N];
    ll dep[N],len[N],mx[N];
    int in[N],out[N],cnt;
    void dfs(int x){
    //	in[x]=++cnt;
    	if (x>m){
    		mx[x]=len[x]=0;
    //		out[x]=cnt;
    		return;
    	}
    	len[x]=INF;
    	for (EDGE *ei=last[x];ei;ei=ei->las){
    		dep[ei->to]=dep[x]+ei->w;
    		fa[ei->to]=x;
    		dfs(ei->to);
    		len[ei->to]+=ei->w;
    		mx[ei->to]=max(mx[ei->to],len[ei->to]);	
    		len[x]=min(len[x],len[ei->to]);
    		mx[x]=max(mx[x],mx[ei->to]);
    	}
    //	out[x]=cnt;
    }
    int p[N];
    bool cmpp(int a,int b){return dep[a+m]<dep[b+m];}
    int q[N],nq;
    int cmpq(int a,int b){return mx[a]>mx[b];}
    int ans[N];
    void cut(ll L){
    	while (nq){
    		int x=q[0];
    		if (mx[x]>L) return;
    		pop_heap(q,q+nq--,cmpq);
    		if (fa[x]){
    			int y=fa[x];
    			if (--deg[y]==0){
    				q[nq++]=y;
    				push_heap(q,q+nq,cmpq);
    			}
    		}
    	}
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1,x,w;i<=n;++i){
    		scanf("%s%d%d",str[i],&x,&w);
    		link(x,i+m,w);
    	}
    	for (int i=1,x,w;i<=m;++i){
    		scanf("%d%d",&x,&w);
    		link(x,i,w);
    	}
    	dfs(0);
    	for (int i=1;i<=n;++i)
    		p[i]=i;
    	sort(p+1,p+n+1,cmpp);
    	for (int i=0;i<=m+n;++i)
    		if (deg[i]==0)
    			q[nq++]=i;
    	make_heap(q,q+nq,cmpq);
    	for (int i=1;i<=n;++i){
    		cut(dep[p[i]+m]);
    		ans[p[i]]=nq;
    	}
    	for (int i=1;i<=n;++i)
    		printf("%s %d
    ",str[i],ans[i]+1);
    	return 0;
    }
    
  • 相关阅读:
    Python——五分钟带你弄懂迭代器与生成器,夯实代码能力
    LeetCode37 使用回溯算法实现解数独,详解剪枝优化
    LeetCode 33,在不满足二分的数组内使用二分的方法
    丰富图文详解B-树原理,从此面试再也不慌
    看完这篇让你高数不挂科之——泰勒公式
    数据结构——动手实战双向链表
    你听说过JMX么
    【网络安全】CSRF攻击详解
    【开发工具】本机安装的JDK8,启动IDEA2019没反应
    Java开发过程中的常用工具类库
  • 原文地址:https://www.cnblogs.com/jz-597/p/14053001.html
Copyright © 2011-2022 走看看