和Leo一起做愛線段樹的好孩子 資料
阿新 • • 發佈:2018-12-09
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
樸素轉移:
我最想的決策單調性明顯不對哇QwQ
得線段樹優化!
不難發現對於j 他是不單調的
但是很明顯他是可以查詢的
構造線段樹查詢區間最小值
然後討論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]; }