【线段树 dp】8.6集合
线段树维护dp
题目大意
给定初始大小为 $N$ 的正整数集合。定义两个数$x$和$y$建立联系的的代价为 $|x-y|$。我们定义整数集合的代价为:将每个整数都与至少一个另外的整数建立联系之后,所有联系的最小代价之和。如果集合大小小于等于1,则代价为 0。
要求动态维护这个正整数集合的代价。
$n \le 200000$
题目分析
常规的线段树维护dp
考虑在权值上处理这个问题:对于一个区间$[l,r]$,在$(l,r)$中的数肯定是自身配对了才优。也就是说一个区间可以被概括成四个状态:$00,01,10,11$其中$0$表示这一个端点暂时没有配对,$1$表示这个端点已经内部配对了。
接下去就是常规的权值线段树处理dp
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 const ll INF = 1ll<<50; 4 const int maxn = 200035; 5 const int LIM = 1000000000; 6 const int maxNode = 8000035; 7 8 struct node 9 { 10 int mn,mx,ls,rs,val; 11 ll f00,f01,f10,f11; 12 }f[maxNode]; 13 int n,m,rt,tot,a[maxn]; 14 int stk[maxn<<2],top; 15 16 int read() 17 { 18 char ch = getchar(); 19 int num = 0, fl = 1; 20 for (; !isdigit(ch); ch=getchar()) 21 if (ch=='-') fl = -1; 22 for (; isdigit(ch); ch=getchar()) 23 num = (num<<1)+(num<<3)+ch-48; 24 return num*fl; 25 } 26 void pushup(int rt) 27 { 28 int l = f[rt].ls, r = f[rt].rs, gap = f[r].mn-f[l].mx; 29 if (!l&&!r){ 30 f[rt].f00 = f[rt].f01 = f[rt].f10 = f[rt].f11 = INF; 31 }else if (!l||!r){ 32 f[rt].mn = f[l+r].mn, f[rt].mx = f[l+r].mx; 33 f[rt].f00 = f[l+r].f00, f[rt].f01 = f[l+r].f01; 34 f[rt].f10 = f[l+r].f10, f[rt].f11 = f[l+r].f11; 35 }else{ 36 f[rt].mn = f[l].mn, f[rt].mx = f[r].mx; 37 f[rt].f00 = std::min(std::min(f[l].f00+f[r].f00+gap, f[l].f00+f[r].f10+gap), std::min(f[l].f01+f[r].f00+gap, f[l].f01+f[r].f10)); 38 f[rt].f01 = std::min(std::min(f[l].f00+f[r].f01+gap, f[l].f00+f[r].f11+gap), std::min(f[l].f01+f[r].f01+gap, f[l].f01+f[r].f11)); 39 f[rt].f10 = std::min(std::min(f[l].f10+f[r].f00+gap, f[l].f10+f[r].f10+gap), std::min(f[l].f11+f[r].f00+gap, f[l].f11+f[r].f10)); 40 f[rt].f11 = std::min(std::min(f[l].f10+f[r].f01+gap, f[l].f10+f[r].f11+gap), std::min(f[l].f11+f[r].f01+gap, f[l].f11+f[r].f11)); 41 } 42 } 43 void insert(int &rt, int l, int r, int c, int w) 44 { 45 if (!rt){ 46 if (top) rt = stk[top--]; 47 else rt = ++tot; 48 f[rt].ls = f[rt].rs = f[rt].val = f[rt].f00 = f[rt].f01 = f[rt].f10 = f[rt].f11 = 0; 49 } 50 f[rt].val += w; 51 if (l==r) f[rt].mn = f[rt].mx = c, f[rt].f11 = INF; 52 else{ 53 int mid = (l+r)>>1; 54 if (c <= mid) 55 insert(f[rt].ls, l, mid, c, w); 56 else insert(f[rt].rs, mid+1, r, c, w); 57 pushup(rt); 58 } 59 if (!f[rt].val) stk[++top] = rt, rt = 0; 60 } 61 int main() 62 { 63 n = read(), m = read(); 64 for (int i=1; i<=n; i++) insert(rt, 0, LIM, read(), 1); 65 for (int i=1; i<=m; i++) 66 { 67 int opt = read()==1?1:-1; 68 insert(rt, 0, LIM, read(), opt); 69 printf("%lld\n",f[1].f11); 70 } 71 return 0; 72 }
END