一道搞了N天的神仙题

题目大意

你现在有M个货物要从根节点运到树上各节点(每个节点只能放一个),每个节点有高度h[i]h[i]h[i],每个货物都有一个高度B[i]B[i]B[i],所以这个货物经过的所有山洞,都不能低于B[i]B[i]B[i]
你现在可以改变一个山洞的高度,问最少增加多少,使得所有货物都能运出去

题解

  • 首先来考虑不开凿情况

    设第iii个能放进num[i]num[i]num[i]个山洞,那么显然满足条件的情况为∀num[i]>=i\forall num[i]>=i∀num[i]>=i,即∀num[i]−i>=0\forall num[i]-i>=0∀num[i]−i>=0
    这东西还是不好维护,再转化一下,就是min(num[i]−i)>=0min(num[i]-i)>=0min(num[i]−i)>=0
    ⟶\longrightarrow⟶这就可以用线段树方便地维护了

  • 接下来考虑开凿

    我们可以二分枚举每一个节点开凿的高度,然后check上面的条件
    当一个h[i]h[i]h[i]改变时,对于numnumnum的影响是一个区间[1,k][1,k][1,k],在B[i]B[i]B[i](有序)上二分得出这个k,在线段树上修改,之后再改回来即可
    复杂度O(N∗log2)O(N*log^2)O(N∗log2)
    然后拼命卡常,仍然卡不进时限。。

  • 继续优化

    线段树的log基本是优不掉了,那能不能把节点的二分给去掉呢?
    考虑一个元素max(B[i])∈{num[i]−i&lt;0}max(B[i])\in \{num[i]-i&lt;0\}max(B[i])∈{num[i]−i<0}
    对于这个东西,在有解的情况下,一定会有一个山洞被改成B[i]B[i]B[i]

    若改B[k]>B[i],则其他B[k]一定是放满的,对于B[i]没有影响
    若改B[k]<B[i],那么只可能让num[i]变得更小,也没用

    所以,只需要枚举每个节点让它变成B[i]B[i]B[i]即可
    复杂度O(N∗log)O(N*log)O(N∗log)
    普通递归式线段树常数巨大,仍然跑得有点慢。。

  • 小Trick

    我们在构造时要构造出

    Min[i]:到根节点路径的最小值
    Min_[i]:到根节点路径的次小值(非严格,更改时要用)
    id[i]:最小值的节点标号

    那么我们贪心想法,按Min[i]Min[i]Min[i]从大到小的顺序枚举节点(此时可行解越来越大)选择
    并且只选择id[i]==i且Min_[i]>Min[i]的节点进行尝试——只有这些节点才会真正产生影响
    然后就跑得比较快乐了~~

Code略长~~

#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define pt(ch) (Top<1000000?St[Top++]=ch:(Out(),St[(Top=0)++]=ch))
#define Out() (fwrite(St,1,Top,stdout))
#define __R register
#define IL inline
using namespace std;
int Top;static char St[1000000],buf[1000000],*p1=buf,*p2=buf;
const int maxn=(5e5)+5,INF=2e9;
int N,Ans,M,Bas,B[maxn],h[maxn];bool vis[maxn];
struct Vector{int tot,lnk[maxn],nxt[maxn<<1],son[maxn<<1];IL void add_e(int x,int y){son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
}T,G;
IL int read(){__R int ret=0;__R char ch=gt();while(ch<'0'||ch>'9') ch=gt();while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();return ret;
}
void write(int x){if(x>9) write(x/10);pt(x%10+'0');}
//SegmentTree
int tag[maxn<<2],P[maxn<<2],Mid[maxn<<2];
#define Ls (i<<1)
#define Rs (Ls|1)
IL int Min(int x,int y){return x<y?x:y;}
IL void Add(int i,int p){P[i]+=p,tag[i]+=p;}
IL void Down(int i){Add(Ls,tag[i]),Add(Rs,tag[i]),tag[i]=0;}
IL void Updata(int i){P[i]=Min(P[Ls],P[Rs]);}
void Build(int i=1,int L=1,int R=M){if(L==R) return (void)(P[i]=L-M-1);Mid[i]=L+R>>1;Build(Ls,L,Mid[i]),Build(Rs,Mid[i]+1,R),Updata(i);
}
void Modify(int x,int y,int p,int i=1,int L=1,int R=M){if(x<=L&&R<=y) return (void)(Add(i,p));if(tag[i]) Down(i);if(x<=Mid[i]) Modify(x,y,p,Ls,L,Mid[i]);if(y>Mid[i]) Modify(x,y,p,Rs,Mid[i]+1,R);Updata(i);
}
int Query(int x,int i=1,int L=1,int R=M){if(L==R) return P[i];if(tag[i]) Down(i);return x<=Mid[i]?Query(x,Ls,L,Mid[i]):Query(x,Rs,Mid[i]+1,R);
}
//只要尝试将所有洞改成max(Bi)∈{num[i]-i<0},因为在有解时,一定要有一个洞被凿成这个Bk
void Find(){for(__R int i=M;i;i--) if(Query(i)<0){Bas=B[i];break;}}
//Build
int A1[maxn],A2[maxn],out[maxn],fuk[maxn];
void Dfs(int x,int fa,int id,int Mi,int Mi_){if(h[x]<=Mi) Mi_=Mi,Mi=h[x],id=x;else if(h[x]<Mi_) Mi_=h[x];A1[x]=Mi,A2[x]=Mi_,T.add_e(id,x),fuk[x]=id;for(__R int j=G.lnk[x];j;j=G.nxt[j]) if(G.son[j]!=fa) Dfs(G.son[j],x,id,Mi,Mi_);
}
IL int Calc(int x,int p){__R int L=1,R=M,mid;while(L<=R) if(B[mid=L+R>>1]<=x) L=mid+1;else R=mid-1;if(R>=1) Modify(1,R,p);return R;
}
int X[maxn],Y[maxn];
IL void Solve(int x){__R int lst=h[x];h[x]=Bas;for(__R int j=T.lnk[x];j;j=T.nxt[j]) X[j]=Calc(A1[x],-1),Y[j]=Calc(Min(A2[T.son[j]],h[x]),1);if(P[1]>=0) Ans=Bas-lst;for(__R int j=T.lnk[x];j;j=T.nxt[j]){if(X[j]>=1) Modify(1,X[j],1);if(Y[j]>=1) Modify(1,Y[j],-1);}h[x]=lst;
}
//XG
int len,id[maxn];
struct ff{int x,y;IL bool operator <(const ff b)const{return y<b.y;}
}hep[maxn];
IL void Put(int x,int y){hep[++len]=(ff){x,y},push_heap(hep+1,hep+1+len);}
IL ff Get(){return pop_heap(hep+1,hep+1+len),hep[len--];}
IL void ReBuild(){int cnt=M;len=0,Put(1,h[1]);while(len&&cnt){__R ff i=Get();vis[i.x]=1,id[++id[0]]=i.x;if(B[cnt]>i.y) break;cnt--;for(int j=G.lnk[i.x];j;j=G.nxt[j]) if(!vis[G.son[j]]) Put(G.son[j],Min(i.y,h[G.son[j]]));}while(len) vis[id[++id[0]]=Get().x]=1;
}
int main(){N=read();for(__R int i=1;i<=N;i++) h[i]=read();for(__R int i=1;i<N;i++){int x=read(),y=read();G.add_e(x,y),G.add_e(y,x);}if((M=read())>N) return puts("-1"),0;for(__R int i=1;i<=M;i++) B[i]=read();sort(B+1,B+1+M),Ans=B[M];Build(),Dfs(1,0,0,INF,INF),ReBuild();for(__R int i=1;i<=N;i++) Calc(A1[i],1);if(P[1]>=0) Ans=0;else{Find();for(int i=1,x;i<=id[0];i++) if(x=id[i],Bas>h[x]&&Bas-h[x]<Ans&&fuk[x]==x&&A2[x]>A1[x]) Solve(x);}if(Ans<B[M]) printf("%d\n",Ans);else puts("-1");return Out(),0;
}

CF533A——题解相关推荐

  1. [JS][dfs]题解 | #迷宫问题#

    题解 | #迷宫问题# 题目链接 迷宫问题 题目描述 定义一个二维数组 N*M ,如 5 × 5 数组下所示: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 1, 1 ...

  2. [JS][dp]题解 | #打家劫舍(一)#

    题解 | #打家劫舍(一)# 题目链接 打家劫舍(一) 题目描述 描述 你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家, ...

  3. [JS]题解 | #魔法数字#

    题解 | #魔法数字# 题目链接 魔法数字 题目描述 牛妹给牛牛写了一个数字n,然后又给自己写了一个数字m,她希望牛牛能执行最少的操作将他的数字转化成自己的. 操作共有三种,如下: 在当前数字的基础上 ...

  4. [JS]题解 | #岛屿数量#

    题解 | #岛屿数量# 题目链接 岛屿数量 题目描述 时间限制:1秒 空间限制:256M 描述 给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右 ...

  5. [JS] 题解:提取不重复的整数

    题解:提取不重复的整数 https://www.nowcoder.com/practice/253986e66d114d378ae8de2e6c4577c1 时间限制:1秒 空间限制:32M 描述 输 ...

  6. 洛谷-题解 P2672 【推销员】

    独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...

  7. [洛谷1383]高级打字机 题解

    题解 这道题一看就珂以用主席树啊 这是一道神奇的题目,那么我们先敲一个主席树,然后维护一个数组len,表示下一次应该在len + 1插入, 之后对于T操作,在上一个版本的len + 1上直接执行插入 ...

  8. luogu P1549 棋盘问题(2) 题解

    luogu P1549 棋盘问题(2) 题解 题目描述 在\(N * N\)的棋盘上\((1≤N≤10)\),填入\(1,2,-,N^2\)共\(N^2\)个数,使得任意两个相邻的数之和为素数. 例如 ...

  9. 【题解搬运】PAT_L1-009 N个数求和

    从我原来的博客上搬运.原先blog作废. (伪)水题+1,旨在继续摸清这个blog(囧 题目 就是求N个数字的和.麻烦的是,这些数字是以有理数"分子/分母"的形式给出的,你输出的和 ...

最新文章

  1. iOS网络缓存扫盲篇
  2. 阿里YunOS总裁张春晖:云芯片将成为IOT的基础
  3. python3.6安装-Linux安装python3.6
  4. python 删除链表中的重复元素
  5. [转载]SQL Server 2005 Data Mining简介
  6. 【渝粤教育】 国家开放大学2020年春季 2773特种动物养殖 参考试题
  7. Halcon学习笔记:1D Measuring一维测量_fuse.hdev灯丝测量示例
  8. 养老金总额和个人账户本息总额啥区别,退休后按照哪个账户计算养老金呢?
  9. python接收163邮件以及下载附件(以163邮箱为例)
  10. 一起学习MySQL(基础阶段已完结)
  11. 完美解决VMware安装后没有VMnet1和VMnet8的问题
  12. Nature Microbiology | 可感染阿斯加德古菌的六种深海沉积物中的病毒基因组
  13. 88e1111 phy芯片在arm平台的配置及接口介绍
  14. threejs制作3d模型展示网页
  15. 女神节礼品:大学男神创作“专属情诗app”
  16. 南京审计大学计算机考研专业课答案
  17. 开源一个健身学习相关的APP,类似Keep
  18. C语言关键字 restrict(一)
  19. 克尼汉的c程序设计语言,c程序设计语言 英文版
  20. CAD图案填充:什么是CAD线图案?

热门文章

  1. 学生DW静态网页设计我的家乡——四川文化(4页) HTML+CSS+JavaScript 家乡主题HTM5网页设计作业成品
  2. Microsoft Edge 开启 IE 模式
  3. matlab绘制矩阵色块图
  4. UTC时间与北京时间的差多久
  5. 小学教师计算机模块报哪些,小学计算机教师个人工作总结
  6. 软件项目生命周期模型
  7. 高等数学笔记-乐经良老师-第四章-微分中值定理和导数的应用-第四节-利用导数研究函数性态
  8. MAGSAC:Marginalizing Sample Consensus
  9. Consistency = Consensus?
  10. 美国AMC数学竞赛的含金量如何?