NOIP2018T1DAY1——Road(并查集做法??)
题目描述
春春是一名道路工程师,负责铺设一条长度为 nnn 的道路。 铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 nnn 块首尾相连的区 域,一开始,第 iii 块区域下陷的深度为 did_idi 。 春春每天可以选择一段连续区间[L,R] [L,R][L,R] ,填充这段区间中的每块区域,让其下陷深 度减少 111。在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为 000 。 春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变 为 000 。
输入输出格式
输入格式:
输入文件包含两行,第一行包含一个整数 nnn,表示道路的长度。 第二行包含 nnn 个整数,相邻两数间用一个空格隔开,第i ii 个整数为 did_idi 。
输出格式:
输出文件仅包含一个整数,即最少需要多少天才能完成任务。
输入输出样例
输入样例#1:
6 4 3 2 5 3 5
输出样例#1:
9
说明
一种可行的最佳方案是,依次选择:[1,6]、[1,6]、[1,2]、[1,1]、[4,6]、[4,4]、[4,4]、[6,6]、[6,6]
对于 30% 的数据,1≤n≤10
对于 70% 的数据,1≤n≤1000
对于 100% 的数据,1≤n≤100000,0≤di≤10000
我估计全NOIP没有人和我一样写并查集的了
可以发现我们可以先把所有最低的先填起来再填高的
这样是没有影响的
每一次把一块填起来就相当于把低的向高的合并,花费是他们的高度差
然后就可以用并查集维护,找左边和右边中的较低合并
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
int n,pos[100005],fa[100005];
struct node{
int l,r,h;
}a[100005];
inline bool comp(int x,int y){
return a[x].h>a[y].h;
}
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int ans;
int main(){
n=read();
for(int i=1;i<=n;i++)a[i].h=read(),a[i].l=i,a[i].r=i,fa[i]=i,pos[i]=i;
sort(pos+1,pos+n+1,comp);
for(int i=1;i<=n;i++){
int f1=find(a[pos[i]].l-1),f2=find(a[pos[i]].r+1),k=find(pos[i]);
if(a[f1].h<a[f2].h){
ans+=a[k].h-a[f2].h,fa[k]=f2,a[f2].l=a[k].l;
}
else {
ans+=a[k].h-a[f1].h,fa[k]=f1,a[f1].r=a[k].r;
}
}
cout<<ans;
}
最后
推广一下另外几篇题解:
DAY1T1:[铺设道路]:(并查集??)
DAY1T2:[货币系统]:(完全背包/搜索)
DAY1T3:[赛道修建]:(二分答案+贪心策略)
DAY2T1:[旅行]:(基环树搜索)
DAY2T2:[填数游戏]:(暴力搜索找规律)
DAY2T3:[保卫王国]:(动态dp+Splay)