codeforce 381 div2

---恢复内容开始---

C:

由mex函数性质可知 ,对任意一个区间,都需要从0开始依次填1,2直到填满,那么,所有区间最小mex的最大值取决于最短区间长度k。

构造a数组之需要从0~k-1依次填数,即a[i] = i%k

代码如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 int n, m;
 7 int main() {
 8     scanf("%d%d", &n, &m);
 9     int len = 10000000;
10     for(int i = 0; i < m; i++) {
11         int x, y;
12         scanf("%d%d
", &x, &y);
13         if(y-x+1 < len) {
14             len = y-x+1;
15         }
16     }
17     printf("%d
", len);
18     printf("%d", 0);
19     for(int i = 1; i < n; i++) {
20         printf(" %d", i%len);
21     }
22     printf("
");
23    return 0;
24 }

D:

思路是预处理出每个结点到根结点的距离dist(x), 然后对每个结点u, 找到一个离根结点最近的祖先v, 且满足 dist(u) - dist(v)<= a[u],

然后将树上区间[v, pa[u]] 的值全部+1, pa[u]为u的直接父亲;

维护树上区间值有两种方法:

方法一 O(nlogn):可以用一个栈来维护当前结点u的全部父亲, 然后用线段树的区间修改来维护区间值, 则结点u的答案为它出栈时在线段树中的值;

方法二 O(n): 对于区间[l, r] ,将区间内容全部加1的简单方法是, 在 l-1 处标记+1, r-1处标记-1,则val[i] += val[i+1]

    对于树上区间[v, u], 只需将sum[pa[v]]--, sum[pa[u]]++, 计算sum[i] = Σ x € {sum[j] | j 是 i 的儿子}

代码如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <vector>
 5 
 6 using namespace std;
 7 typedef long long LL;
 8 
 9 const int maxn = 2e5 + 10;
10 vector<int> G[maxn];
11 vector<int> S;
12 int a[maxn];
13 LL d[maxn];     //节点到1的距离
14 int w[maxn];     //节点到父亲的距离
15 int ans[maxn];
16 int n;
17 int p[maxn];
18 void cal_d(int u, LL dist) {
19     d[u] = dist;
20     for(int i = 0; i < G[u].size(); i++) {
21         int v = G[u][i];
22         cal_d(v, dist+w[v]);
23     }
24 }
25 int b_search(int cur, LL val, int L, int R) {
26     while(L < R) {
27         int M = L + (R-L)/2;
28         if(d[cur]-d[S[M]] <= val) R = M;
29         else L = M+1;
30     }
31     return L;
32 }
33 void dfs_upd(int u) {
34     if(!S.empty()) {
35         int k = b_search(u, a[u], 0, S.size());
36         if(k < S.size()) {
37             int v = S[k];    
38             ans[p[v]]--;
39             ans[p[u]]++;
40         }
41     }
42     S.push_back(u);
43     for(int i = 0; i < G[u].size(); i++) 
44         dfs_upd(G[u][i]);
45     S.pop_back();
46 }
47 
48 void dfs_ans(int u) {
49     int &t = ans[u];
50     for(int i = 0; i < G[u].size(); i++) {
51         int v = G[u][i];
52         dfs_ans(v);
53         t += ans[v];
54     }
55 }
56 
57 int main() {
58     scanf("%d", &n);
59     for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
60     for(int i = 2; i <= n; i++) {
61         scanf("%d%d", &p[i], &w[i]);
62         G[p[i]].push_back(i);
63     }
64     cal_d(1, 0);
65     dfs_upd(1);
66     dfs_ans(1);
67     printf("%d", ans[1]);
68     for(int i = 2; i <= n; i++) printf(" %d", ans[i]);
69     printf("
");
70 }

E:

Let's consider the difference between two adjacent elements of array: a[i] = arr[i + 1] - arr[i]. Let us add d in the segment from l to r. Then it is clear that in the array a will change no more than two values ​​(at the ends of the addition of the segment), because if l < i < r, then a[i] = arr[i + 1] + d - (arr[i] + d) = arr[i + 1] - arr[i]. Note that the answer is a sequence of positive elements of a + a sequence of negative elements of a (i.e., ... +1 +1 +1 +1 -1 -1 ..., as the mountain first increases and then decreases). To solve this problem it's enough to take the tree segments and store at each vertex response to the prefix, suffix, and the middle. Two segments [l; m] and [m + 1; r] can be merged in case sign(a[m + 1]) ≤ sign(a[m]) and they are not equal to zero.

suffix  + 1 + 1 + 1 + 1 - 1 - 1 - 1 - 1 и  - 1 - 1 - 1 - 1 can be merged with prefix  - 1 - 1 - 1 - 1

suffix  + 1 + 1 + 1 + 1 can be merged with prefix  - 1 - 1 - 1 - 1 or prefix  + 1 + 1 + 1 + 1 - 1 - 1 - 1 - 1

译文:

让我们考虑数组中两个相邻元素的差值:a[i] = arr[i + 1] - arr[i] (arr即为题中的初始塔高度)。让我们将区间[l, r]加上 d。显然, 数组 a 将有不超过两个值发生改变(位于区间的两个端点),因为 假若 l < i < r ,那么 a[i] = arr[i + 1] + d - (arr[i] + d) = arr[i + 1] - arr[i] 。注意到答案是由a中一段正数序列和一段负数序列组成(例如,... +1 +1 +1 +1 -1 -1 ... , 因为山顶先上升后下降)。为了解决这个问题, 构造一颗线段树, 每个结点储存相应区间的前缀prefix, 后缀suffix, 以及中值middle。 两个区间[l; m] 和[m+1; r]能合并 当且仅当  sign(a[m + 1]) ≤ sign(a[m]) && a[m] != 0 && a[m+1] != 0

注意:线段树要开4*N

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 
  5 using namespace std;
  6 
  7 const int maxn = 3e5 + 10;
  8 typedef long long LL;
  9 int arr[maxn];
 10 LL a[maxn];
 11 
 12 int n, m;
 13 
 14 int max_suf[4*maxn], max_pre[4*maxn], max_wid[4*maxn];
 15 int sign(LL x) {return x < 0 ? -1 : 1;}
 16 
 17 int S(int i, int j) {return j - i + 1;}
 18 int p;
 19 int upd_wid(int o, int L, int R) {
 20     int M = L + (R-L)/2;
 21     if(L == R) return max_wid[o] = a[L] ? 1 : 0;
 22     else {
 23         int w1, w2, w3;
 24         if(p <= M) {
 25              w1 = upd_wid(2*o, L, M);
 26              w2 = max_wid[2*o+1];
 27         }
 28         else {
 29             w1 = max_wid[2*o];    
 30             w2 = upd_wid(2*o+1, M+1, R);
 31         }
 32     
 33         w3 = a[M] && a[M+1] && sign(a[M+1]) <= sign(a[M]) ? S(max_suf[2*o], M) + S(M+1, max_pre[2*o+1]) : 0;
 34         int ans = max(w1, w2);
 35         ans = max(ans, w3);
 36         return max_wid[o] = ans;
 37     }
 38 }
 39 int upd_suf(int o, int L, int R) {
 40     int M = L + (R-L)/2;
 41     if(L == R) return max_suf[o] = L;
 42     else {
 43         int s1, s2;
 44         if(p <= M) {
 45             s1 = upd_suf(2*o, L, M);
 46             s2 = max_suf[2*o+1];
 47         }
 48         else {
 49             s2 = upd_suf(2*o+1, M+1, R);
 50             s1 = max_suf[2*o];
 51         }
 52         int ans = s2;
 53         if(s2 == M+1 && a[M] && a[M+1] && sign(a[M+1]) <= sign(a[M])) ans = s1;
 54         return max_suf[o] = ans;
 55     }
 56 }
 57 int upd_pre(int o, int L, int R) {
 58     int M = L + (R-L)/2;
 59     if(L == R) return max_pre[o] = L;
 60     else {
 61         int p1, p2;
 62         if(p <= M) {
 63             p1 = upd_pre(2*o, L, M);
 64             p2 = max_pre[2*o+1];
 65         }
 66         else {
 67             p2 = upd_pre(2*o+1, M+1, R);
 68             p1 = max_pre[2*o];
 69         }
 70         int ans = p1;
 71         if(p1 == M && a[M] && a[M+1] && sign(a[M+1]) <= sign(a[M])) ans = p2;
 72         return max_pre[o] = ans;
 73     }
 74 }
 75 
 76 
 77 int main() {
 78     
 79     scanf("%d", &n);
 80     for(int i = 1; i <= n; i++) scanf("%d", &arr[i]);
 81     for(int i = 1; i < n; i++) {
 82         a[i] = arr[i+1] - arr[i];
 83         p = i;
 84         upd_pre(1, 1, n-1);
 85         upd_suf(1, 1, n-1);
 86         upd_wid(1, 1, n-1);
 87     }
 88     scanf("%d", &m);
 89     for(int i = 1; i <=m; i++) {
 90         int l, r, v;
 91         scanf("%d%d%d", &l, &r, &v);
 92         int wid;
 93         if(n != 1) {
 94         p = l-1;
 95         a[l-1] += v;
 96         upd_pre(1, 1, n-1);
 97         upd_suf(1, 1, n-1);
 98         upd_wid(1, 1, n-1);
 99         p = r;
100         a[r] -= v;
101         upd_pre(1, 1, n-1);
102         upd_suf(1, 1, n-1);
103         upd_wid(1, 1, n-1);
104         wid = max_wid[1]+1;
105         }
106         else wid = 1;
107         printf("%d
", wid);
108     }
109     return 0;
110 }
原文地址:https://www.cnblogs.com/Kiraa/p/6113394.html