1. 程式人生 > >和Leo一起做愛線段樹的好孩子 資料

和Leo一起做愛線段樹的好孩子 資料

Mr_H出了一道資訊學競賽題,就是給n個數排序。輸入格式是這樣的:試題有若干組資料。每組資料的第一個是一個整數n,表示總共有n個數待排序;接下來n個整數,分別表示這n個待排序的數。   例如:3 4 2 –1 4 1 2 3 4,就表示有兩組資料。第一組有3個數 (4,2,-1),第二組有4個數(1,2,3,4)。可是現在 Mr_H做的輸入資料出了一些問題。例如:2 1 9 3 2 按理說第一組數 據有2個數(1,9),第二組資料有3個數,可是“3”後面並沒有出現三個數,只出現了一個數“2” 而已!   現在Mr_H需要對資料進行修改,改動中“一步”的含義是對檔案中的某一個數+1或-1,寫個程式,計算最少需要多少步才能將資料改得合法。

線段樹優化DP

樸素轉移:

F_{j}=\sum_{i}^{j-1}F_{i}+\left | j-i-1-a_{i+1} \right |

我最想的決策單調性明顯不對哇QwQ

得線段樹優化!

不難發現對於j B_{i}=A_{i}+i他是不單調的

但是很明顯他是可以查詢的

構造線段樹查詢區間最小值

然後討論abs的展開所以需要兩棵線段樹

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define lc (p<<1)
#define rc (p<<1|1)
const int INF=1e9+7;
const int N=2e6+10;
int A[N];
int B[N];
int F[N];
int m;
struct Node{
	int lson,rson,sum;
}T[2][N];
void Build(int Id,int p,int l,int r){
	T[Id][p].lson=l;
	T[Id][p].rson=r;
	T[Id][p].sum=INF;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(Id,lc,l,mid);
	Build(Id,rc,mid+1,r);
}
void PushUp(int Id,int p){
	T[Id][p].sum=min(T[Id][lc].sum,T[Id][rc].sum);
}
void Update(int Id,int p,int pos,int val){
	if(T[Id][p].lson==pos&&pos==T[Id][p].rson){
		T[Id][p].sum=min(T[Id][p].sum,val);
		return;
	}
	int mid=(T[Id][p].lson+T[Id][p].rson)>>1;
	if(pos<=mid)Update(Id,lc,pos,val);
	else Update(Id,rc,pos,val);
	PushUp(Id,p);
}
int Query(int Id,int p,int l,int r){
	if(l>r)return INF;
	if(l<=T[Id][p].lson&&T[Id][p].rson<=r){
		return T[Id][p].sum;
	}
	int ret=INF;
	int mid=(T[Id][p].lson+T[Id][p].rson)>>1;
	if(l<=mid)ret=min(ret,Query(Id,lc,l,r));
	if(mid< r)ret=min(ret,Query(Id,rc,l,r));
	return ret;
}
int main(){
//	freopen("test.in","r",stdin);
	scanf("%d",&m);
	for(int i=1;i<=m;++i)scanf("%d",&A[i]),B[i]=A[i]+i-1;
	int len=1e5+1e4+10;
	Build(0,1,-len,len);
	Build(1,1,-len,len);
	Update(0,1,A[1],-A[1]);
	Update(1,1,A[1],A[1]);		
	for(int i=1;i<=m;++i){
//		cout<<Query(0,1,1,i-1)<<" "<<Query(1,1,i,len)<<'\n';
		F[i]=min(Query(0,1,-len,i-1)+i-1,Query(1,1,i,len)+1-i);
		Update(0,1,A[i+1]+i,F[i]-A[i+1]-i);
		Update(1,1,A[i+1]+i,F[i]+A[i+1]+i);
	}
	cout<<F[m];
}