专栏文章
题解:P11673 [USACO25JAN] Median Heap G
P11673题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqccyn4
- 此快照首次捕获于
- 2025/12/04 02:29 3 个月前
- 此快照最后确认于
- 2025/12/04 02:29 3 个月前
dp 题。
首先先把 和 离散化,变成 之间的数。
现在来分析这一“近似中位数”的特性:不妨设当前节点为 , 表示 的子树操作完后, 这个节点上的值是多少。那么 的充要条件是 (替换操作进行完之后的 值,与原来的 做区分),, 中,恰好有一个小于等于 ,一个等于 ,一个大于等于 。
此时,就能自然而然地设出一个 dp 的状态:设 表示希望令 ,至少需要在子树内支付多少代价。但是我们发现直接这样设好像无法转移,还需要两个辅助数组: 表示希望令 的最小代价, 表示希望令 的最小代价。转移方程比较繁琐,但不难推导(具体见文末的代码的
push_down 函数
)。就这样,我们有了一个 的做法。但是这样只能拿到 个测试点的分数,显然不够。
然而,如果考虑 的值从 变成 ,会发现实际上 值变化的点很少。对于所有 以及 的 ,只有 以及他到根的节点的值可能会变!由于这些数加起来一共只有 个,所以在 从 一直移动到 的过程中总共只需要改变 个位置的 值。
所以我们可以添加一个优化,只在 中更改 或 的 到根的路径上的节点的 值,从而得到 ,经过优化后的复杂度为 。不明白为什么开 4 秒……
CPPint n,q;
const int MAXN=2e6+5;
int a[MAXN],c[MAXN];
int p[MAXN],l,now;
int d[MAXN];
vector<int>que[MAXN],poi[MAXN];
ll tox[MAXN],toe[MAXN],tod[MAXN];//tox:文中的 dp1,toe:文中的 dp,tod:文中的 dp2
void push_up(int x){//转移方程
tox[x]=min({tox[x<<1]+(a[x]>now)*c[x],tox[x<<1|1]+(a[x]>now)*c[x],tox[x<<1]+tox[x<<1|1]});
tod[x]=min({tod[x<<1]+(a[x]<now)*c[x],tod[x<<1|1]+(a[x]<now)*c[x],tod[x<<1]+tod[x<<1|1]});
toe[x]=min({min(tox[x<<1]+tod[x<<1|1],tod[x<<1]+tox[x<<1|1])+(a[x]!=now)*c[x],
toe[x<<1]+min((a[x]>now)*c[x]+tod[x<<1|1],(a[x]<now)*c[x]+tox[x<<1|1]),
toe[x<<1|1]+min((a[x]>now)*c[x]+tod[x<<1],(a[x]<now)*c[x]+tox[x<<1])});
}
ll ans[MAXN];
void dfs(int x){
if(x>n){
toe[x]=1e18;
return ;
}
if((x<<1)>n){
toe[x]=(a[x]!=now)*c[x];
tod[x]=(a[x]<now)*c[x];
tox[x]=(a[x]>now)*c[x];
}else{
dfs(x<<1);dfs(x<<1|1);
push_up(x);
}
// printf("%d %d %d %lld %lld %lld\n",x,a[x],c[x],tod[x],tox[x],toe[x]);
}
void pus(int x){
if(!x)return ;
if(x*2>n){
toe[x]=(a[x]!=now)*c[x];
tod[x]=(a[x]<now)*c[x];
tox[x]=(a[x]>now)*c[x];
}else{
push_up(x);
}
pus(x>>1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&c[i]);
p[++l]=a[i];
}scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&d[i]);p[++l]=d[i];
}
//离散化
sort(p+1,p+1+l);
l=unique(p+1,p+1+l)-p-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(p+1,p+1+l,a[i])-p;
poi[a[i]].push_back(i);
}
for(int i=1;i<=q;i++){
d[i]=lower_bound(p+1,p+1+l,d[i])-p;
que[d[i]].push_back(i);
}
dfs(1);
// now=4;
// dfs(1);
for(int i=1;i<=l;i++){
now=i;
// dfs(1);
for(int j=0;j<poi[i-1].size();j++){
pus(poi[i-1][j]);
}
for(int j=0;j<poi[i].size();j++){
pus(poi[i][j]);
}
for(int j=0;j<que[i].size();j++){
ans[que[i][j]]=toe[1];
}
// printf("now=%d:\n",i);
// for(int j=1;j<=n;j++){
// printf("%d %d %d %lld %lld %lld\n",j,a[j],c[j],tox[j],toe[j],tod[j]);
// }
}
for(int i=1;i<=q;i++){
printf("%lld\n",ans[i]);
}
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...