BZOJ 3747: [POI2015]Kinoman

 

考虑枚举起点,找一个最远的右端点使得以这个点为起点的答案最大

用线段树维护,需要设计一种标记,使得含有多个数的前缀中减去这个数的贡献

考虑这样设计,对于第一次出现的数,对其赋值$w[i]$

第二次出现 赋值$-w[i]$

第三次出现 赋值为0

这样前缀和就满足多次出现的数不会计算贡献

再维护前驱节点和后驱节点,每次删去开头的数,维护一下后驱节点

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 1000010
 6 #define INF 0x3f3f3f3f3f3f3f3f
 7 int n, m, f[N], pre[N], nx[N];
 8 ll w[N], v[N];
 9 map <int, int> mp;
10 
11 namespace SEG
12 {
13     ll Max[N << 2], lazy[N << 2];
14     void init()
15        { 
16         memset(Max, 0, sizeof Max);
17         memset(lazy, 0, sizeof lazy);   
18     }
19     void pushdown(int id)
20     {
21         if (!lazy[id]) return;
22         lazy[id << 1] += lazy[id];
23         Max[id << 1] += lazy[id];
24         lazy[id << 1 | 1] += lazy[id];
25         Max[id << 1 | 1] += lazy[id]; 
26         lazy[id] = 0;
27     }
28     void update(int id, int l, int r, int ql, int qr, ll val)
29     {
30         if (l >= ql && r <= qr) 
31         {
32             lazy[id] += val;
33             Max[id] += val;
34             return;
35         }
36         pushdown(id); 
37         int mid = (l + r) >> 1;
38         if (ql <= mid) update(id << 1, l, mid, ql, qr, val);
39         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val);
40         Max[id] = max(Max[id << 1], Max[id << 1 | 1]); 
41     }
42 }
43 
44 int main()
45 {
46     while (scanf("%d%d", &n, &m) != EOF)
47     {
48         for (int i = 1; i <= n; ++i) scanf("%d", f + i);
49         for (int i = 1; i <= m; ++i) scanf("%lld", w + i);
50         mp.clear();
51         for (int i = 1; i <= n; ++i)
52         {
53             if (mp.find(f[i]) != mp.end())
54                 pre[i] = mp[f[i]];
55             else
56                 pre[i] = 0;
57             mp[f[i]] = i;
58         }
59         mp.clear(); 
60         for (int i = n; i >= 1; --i)
61         {
62             if (mp.find(f[i]) != mp.end())
63                 nx[i] = mp[f[i]];
64             else
65                 nx[i] = n + 1;
66             mp[f[i]] = i;
67         }
68         for (int i = 1; i <= n; ++i)
69         {
70             if (pre[i] == 0) v[i] = w[f[i]];
71             else if (v[pre[i]] == w[f[pre[i]]]) v[i] = -w[f[i]]; 
72             else v[i] = 0;
73         }
74         SEG::init();
75         for (int i = 1; i <= n; ++i)
76             SEG::update(1, 1, n, i, n, v[i]);
77         ll res = 0;
78         for (int i = 1; i <= n; ++i)
79         {
80             res = max(res, SEG::Max[1]);
81             SEG::update(1, 1, n, i, n, -v[i]);
82             if (nx[i] != n + 1)
83             {
84                 SEG::update(1, 1, n, nx[i], n, -v[nx[i]]);
85                 v[nx[i]] = w[f[nx[i]]];
86                 SEG::update(1, 1, n, nx[i], n, v[nx[i]]);
87                 if (nx[nx[i]] != n + 1)
88                 {
89                     v[nx[nx[i]]] = -v[nx[i]];
90                     SEG::update(1, 1, n, nx[nx[i]], n, -v[nx[i]]);
91                 }
92             }
93         }
94         printf("%lld\n", res);
95     }
96     return 0;
97 }
View Code

 

posted @ 2018-11-24 22:51  Dup4  阅读(146)  评论(0编辑  收藏  举报