P4253 [SCOI2015] 小凸玩密室
将状态刻画为 \(f_{i,j}\) 表示点亮完 \(i\) 的子树,然后去到 \(j\) 的最小代价。转移是好做的。每个点再点亮完祂的子树后只有可能去到祂的祖先或祖先的儿子,因为给出的树是完全二叉树,所以状态数是 \(n\log(n)\)。
但是题目有一个很耐受的条件:可以任选一个点开始。考虑枚举起点,然后暴力向上跳,并把另一个子树的信息合并上来,由于树高为 \(\log(n)\) 所以时间复杂度还是 \(n\log(n)\)。但是我在实现的时候用了 map 所以总时间复杂度变成了 \(n\log^2(n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define int long long
const int maxn=200010;
int n,a[maxn],b[maxn],deep[maxn],sy[maxn];
map<int,int>f[maxn];
int dfs(int u,int mb){
if(f[u].find(mb)!=f[u].end()) return f[u][mb];
int ls=u<<1,rs=u<<1|1,ans,ans2;
if(ls>n) return deep[u]*a[mb];
if(rs>n) return deep[ls]*a[mb]+a[ls]*b[ls];
{
ans=dfs(ls,rs);
ans+=a[ls]*b[ls];
ans+=deep[rs]*a[rs]-2*a[rs]*deep[u];
ans+=dfs(rs,mb);
}
{
ans2=dfs(rs,ls);
ans2+=a[rs]*b[rs];
ans2+=deep[ls]*a[ls]-2*a[ls]*deep[u];
ans2+=dfs(ls,mb);
}
return f[u][mb]=min(ans,ans2);
}
void get_deep(int u){
if((u<<1)<=n) deep[u<<1]=deep[u]+b[u<<1],get_deep(u<<1);
if((u<<1|1)<=n) deep[u<<1|1]=deep[u]+b[u<<1|1],get_deep(u<<1|1);
}
int js(int u){
int fa=(u>>1),ans=dfs(u,fa)-deep[fa]*a[fa];
int lt=(u&1);
u=fa;
while(u){
int fa=(u>>1);
int ls=(u<<1),rs=(u<<1|1);
if(lt){
if(ls<=n){
ans+=a[ls]*b[ls];
ans+=dfs(ls,fa)-deep[fa]*a[fa];
}
else ans+=a[fa]*b[u];
}
else{
if(rs<=n){
ans+=a[rs]*b[rs];
ans+=dfs(rs,fa)-deep[fa]*a[fa];
}
else ans+=a[fa]*b[u];
}
lt=(u&1);
u=fa;
}
return ans;
}
signed main(){
read(n);
if(n==1){
write(0);
return 0;
}
for(int i=1;i<=n;i++) read(a[i]);
for(int i=2;i<=n;i++) read(b[i]);
if(n==2){
write(min(a[1]*b[2],a[2]*b[2]));
return 0;
}
get_deep(1);
int ans=1000000000000000000;
for(int i=1;i<=n;i++) ans=min(ans,js(i));
write(ans);
return 0;
}

浙公网安备 33010602011771号