zoukankan      html  css  js  c++  java
  • SCOI2015 小凸玩密室

    小凸玩密室

    小凸和小方相约玩密室逃脱,这个密室是一棵有(n)个节点的完全二叉树,每个节点有一个灯泡。点亮所有灯泡即可逃出密室。每个灯泡有个权值(a_i),每条边也有个权值(b_i)

    点亮第(1)个灯泡不需要花费,之后每点亮一个新的灯泡(v)的花费,等于上一个被点亮的灯泡(u)到这个点(v)的距离(operatorname{dist}(u, v)),乘以这个点的权值(a_v)

    在点灯的过程中,要保证任意时刻所有被点亮的灯泡必须连通,在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡。请告诉他们,逃出密室的最少花费是多少。

    (1 leq n leq 2 imes 10 ^ 5, 1 < a_i, b_i leq 10 ^ 5)

    题解

    https://www.cnblogs.com/CXCXCXC/p/5312237.html

    (f(x,y))表示走完(x)及其子树再走到(y)的最小代价。考虑转移方式,

    • 如果(x)是叶子节点,那么答案就是(a_yoperatorname{dist}(x,y))

    • 如果(x)只有左孩子,就先遍历左子树,状态转移是(a_{ ext{lc}}b_{ ext{lc}}+f( ext{lc},y))

    • 如果两个孩子都有,就考虑是先转移到左孩子还是右孩子,(f(x,y)=min(a_{ ext{lc}}b_{ ext{lc}}+f( ext{lc}, ext{rc})+f( ext{rc},y),a_{ ext{rc}}b_{ ext{rc}}+f( ext{rc}, ext{lc})+f( ext{lc},y)))

    题目数据范围很大,这样的转移肯定在时间和空间上都不行。

    但是发现很多(x,y)是不合法的,比如(y)肯定不能是(x)的子节点。由此考虑有意义的(x,y),可以发现,(y)一定是某个(x)的祖先的另一个儿子,

    所以重新定义(f(x,i))为走完(x)及其子树到深度为(i)的节点的子节点的最小代价。

    (g(x,i))表示走完(x)的子树再走到(x)的深度为(i)的祖先的最小代价。转移:

    • 叶子:(g(x,i)=a_yoperatorname{dist}(x,y))

    • 只有左孩子:(g(x,i)=a_{ ext{lc}}b_{ ext{lc}}+g( ext{lc},i))

    • 左右孩子都有:(g(x,i)=min(a_{ ext{lc}}b_{ ext{lc}}+f( ext{lc}, ext{dep}_x)+g( ext{rc},i),a_{ ext{rc}}b_{ ext{rc}}+f( ext{rc}, ext{dep}_x)+g( ext{lc},i)))

    最后就是统计答案了,我们选定一个节点(x)作为第一个点亮的灯,然后统计其子树的答案,再走到(x)的父节点,再走(x)的兄弟节点……以此类推。

    由于(f)(g)的第一维都是(n),第二维都是(log n),所以总的时间复杂度是(O(nlog n))

    CO int N=2e5+10;
    int a[N],b[N],dep[N],dis[N];
    int f[N][19],g[N][19];
    
    signed main(){
    	int n=read<int>();
    	for(int i=1;i<=n;++i) read(a[i]);
    	for(int i=2;i<=n;++i) read(b[i]);
    	dep[1]=1;
    	for(int i=2;i<=n;++i) dep[i]=dep[i>>1]+1,dis[i]=dis[i>>1]+b[i];
    	for(int x=n;x>=1;--x)for(int i=0;i<dep[x];++i){
    		int lc=x<<1,rc=x<<1|1;
    		int y=x>>(dep[x]-i-1)^1;
    		if(lc>n) f[x][i]=a[y]*(dis[x]+dis[y]-2*dis[y>>1]);
    		else if(rc>n) f[x][i]=a[lc]*b[lc]+f[lc][i];
    		else f[x][i]=min(a[lc]*b[lc]+f[lc][dep[x]]+f[rc][i],a[rc]*b[rc]+f[rc][dep[x]]+f[lc][i]);
    	}
    	for(int x=n;x>=1;--x)for(int i=0;i<=dep[x];++i){
    		int lc=x<<1,rc=x<<1|1;
    		int y=x>>(dep[x]-i);
    		if(lc>n) g[x][i]=a[y]*(dis[x]-dis[y]);
    		else if(rc>n) g[x][i]=a[lc]*b[lc]+g[lc][i];
    		else g[x][i]=min(a[lc]*b[lc]+f[lc][dep[x]]+g[rc][i],a[rc]*b[rc]+f[rc][dep[x]]+g[lc][i]);
    	}
    	int ans=g[1][0];
    	for(int i=2;i<=n;++i){
    		int sum=g[i][dep[i]-1];
    		for(int x=i;x>1;x>>=1){
    			int y=x^1,z=x>>1;
    			if(y>n) sum+=a[z>>1]*b[z];
    			else sum+=a[y]*b[y]+g[y][dep[z]-1];
    		}
    		ans=min(ans,sum);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Shiro SessionContext和SessionKey的设计概念
    Shiro DefaultWebSessionManager的设计概念
    Shiro SessionDAO的设计概念
    Shiro DefaultSessionManager的设计概念
    Shiro 关于校验Session过期、有效性的设计概念
    Shiro AbstractValidatingSessionManager设计概念
    Windows 查看端口及杀掉进程
    Shiro Session及SessionManager的设计概念
    jQuery操作DOM节点
    jQuery动画效果
  • 原文地址:https://www.cnblogs.com/autoint/p/13064349.html
Copyright © 2011-2022 走看看