A. 偷懒的小X(lazy)
题目大意:给出一个长度为n的数列,要求将答案数列按顺序放进小根堆中。
解法:分治。选择较小段[L+1,mid]放入右儿子2*p+1,选择较大段[mid+1,L]放入小儿子
#include<bits/stdc++.h>
#define int long long
#define go(p) int ls=p<<1,rs=p<<1|1;
using namespace std;
const int N = 1e6 + 10;
int n,a[N],b[N],t[N],root;
void dfs(int p,int l,int r){
t[p]=a[l];
if(l==r) return;
int mid=l+r>>1;
dfs(p<<1,mid+1,r);dfs(p<<1|1,l+1,mid);
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
dfs(1,1,n);
for(int i=1;i<=n;++i) cout<<t[i]<<" ";
return 0;
}
B. 渡河(river)
题目大意:给出若干个点,求走到地图边界的最小代价。其中从0-1贡献+1
解法:从边界往中间搜,记录到每个点的最小值
#include<bits/stdc++.h>
#define int long long
#define go(p) int ls=p<<1,rs=p<<1|1;
using namespace std;
const int N = 1e3 + 10;
const int dx[8] = { 1, 0, -1, 0, 1, 1, -1, -1 };
const int dy[8] = { 0, 1, 0, -1, 1, -1, 1, -1 };
int a[N][N];
int n,Q;
int b[N][N],v[N][N],dis[N][N];
struct node{
int x,y;
}d[N];
int qx[N*N],qy[N*N];
void bfs(int x, int y, int z) {
qx[1] = x, qy[1] = y;
int head = 1, tail = 1, ans = 2147483647;
while (head <= tail) {
for (int j = 0; j < 8; ++j) {
int X = qx[head] + dx[j], Y = qy[head] + dy[j];
if (b[X][Y] && !v[X][Y] && a[X][Y] == z)
v[X][Y] = 1, qx[++tail] = X, qy[tail] = Y;
else if (!b[X][Y])
ans = min(ans, dis[X][Y] + a[X][Y]);
}
++head;
}
for (int i = 1; i <= tail; ++i) b[qx[i]][qy[i]] = 0, dis[qx[i]][qy[i]] = ans;
}
void solve(){
int bx,by;
cin>>bx>>by;
cout<<dis[bx][by]<<" ";
}
signed main(){
cin>>n>>Q;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;a[i][j]=c-48;
b[i][j]=1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(b[i][j])
bfs(i,j,a[i][j]);
}
}
while(Q--) solve();
return 0;
}
C. 进击的巨人
题目大意:求经过m次加法后的数列最小值
解法:差分板子
#include<bits/stdc++.h>
#define int long long
#define go(p) int ls=p<<1,rs=p<<1|1;
using namespace std;
const int N = 1e6 + 10;
int n,m,a[N],s[N];
void insert(int l,int r,int p){
s[l]+=p;s[r+1]-=p;
}
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
insert(i,i,a[i]);
}
for(int i=1,l,r,k;i<=m;i++){
cin>>l>>r>>k;
insert(l,r,k);
}
for(int i=1;i<=n;i++) s[i]+=s[i-1];
for(int i=1;i<=n;i++) cout<<s[i]<<" ";
return 0;
}
D. 电缆建设
题目大意:给出若干个分布在两个竖直平面上的点,求连成连通图的最小代价
解法:将每个点与它相邻的点和另外平面的最近的两个距离点连有向边,在图上跑最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int n,m,Lx,Rx,d,cnt,cx[N];
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-48;ch=getchar();
}return x*f;
}
struct node{
int x,y;
double val;
}e[N<<2];
struct num{
double x,y;
}a[N];
double dis(double bx,double by,double ex,double ey){
return sqrt((bx-ex)*(bx-ex)+(by-ey)*(by-ey));
}
void add(int X,int Y){
e[++cnt]={X,Y,dis(a[X].x,a[X].y,a[Y].x,a[Y].y)};
}
void build(){
for(int i=2;i<=n;i++) add(i-1,i);
for(int i=n+2;i<=d;i++) add(i-1,i);
for(int i=1;i<=n;i++){
int p=lower_bound(cx+1,cx+m+1,a[i].y)-cx;p+=n;
if(p-1>=n+1) add(i,p-1);
if(p+1<=d) add(i,p+1);
add(i,p);
}
}
int fa[N<<2];
int find(int x){
if(fa[x]!=x) return fa[x]=find(fa[x]);
else return x;
}
inline bool cmp(node p,node q){
return p.val<q.val;
}
void solve(){
double ans=0;int tot=0;
for(int i=1;i<=d;i++) fa[i]=i;
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
int fx=find(e[i].x),fy=find(e[i].y);
if(fx==fy) continue;
++tot;fa[fx]=fy;ans+=e[i].val;
if(tot==d-1) break;
}
printf("%.2f",ans);
}
int main(){
n=read();m=read();Lx=read();Rx=read();
int sumy=0;d=n+m;
for(int i=1,k;i<=n;i++){
k=read();sumy+=k;
a[i]={Lx,sumy};
}sumy=0;
for(int i=1,k;i<=m;i++){
k=read();sumy+=k;
a[n+i]={Rx,sumy};cx[i]=sumy;
}
build();
solve();
return 0;
}