Codeforces Round #225 (Div. 2) 题解
C. Milking cows
题意:有n头奶牛,横着占城一排,0表示奶牛的头朝左,1表示奶牛的头朝右,每只奶牛身上有无线的奶,现在需要对每只内牛挤奶,假设对奶牛i挤奶,看到这只奶牛的奶牛会流失1个奶,被挤过的奶牛不会流失,问挤完n只奶牛,最少会流失多少奶。
思路:从左向右处理ai为1的前缀和,从右到左处理ai为0的前缀和,因为最优的挤奶方法肯定是,先把一种内牛挤完,并且使同种奶牛不会受到惊吓,如果同种奶牛受到惊吓肯定不是最优的,然后分别处理从左向右挤种类为1的奶牛,从右向左种类为0的奶牛,对两种答案取最小值
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 7; int a[maxn], L[maxn], R[maxn]; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = 1; i <= n; i++) { L[i] = L[i - 1] + (a[i] == 1); } for(int i = n; i; i--) { R[i] = R[i + 1] + (a[i] == 0); } long long ans1 = 0, ans2 = 0; for(int i = 1; i <= n; i++) if(a[i] == 1) ans1 += R[i]; for(int i = n; i; i--) if(a[i] == 0) ans2 += L[i]; cout << min(ans1, ans2) << endl; return 0; }
D. Volcanoes
题意:在一个n*n(1e9)的地图上,有一个人开始的时候在左上角1,1,他想走到右下角n,n,他只能向下和向右走,地图上有m(1e5)个点不能走,问这个人最少走几步可以到右下角,如果不能打印-1
思路:把不能走的点按照y从小到大x从小到大排序,每次处理相邻两行可以走到的区间,如果有一行没有可以走到的区间就打印-1,如果可以走到最后,那么答案就是2*n-2
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 7; struct node { int x, y; }a[maxn], pre[maxn], now[maxn]; int n, m; bool cmp(node a, node b) { if(a.y == b.y) return a.x < b.x; return a.y < b.y; } bool check() { int cnt = 1; pre[0].x = 1, pre[0].y = 1; for(int i = 0; i < m; i++) { if(a[i].y != a[i - 1].y + 1) { cnt = 1; pre[0].y = n; } int k; for(k = i + 1; a[k].y == a[i].y; k++); k--; int num = 0; int res = 0; for(int j = i; j <= k; j++) { if(a[j].x > res + 1) { now[num].x = res + 1;now[num].y = a[j].x - 1; num ++; } res = a[j].x; } if(n > res) { now[num].x = res + 1; now[num].y = n; num++; } int t = 0; for(int j = 0; j < cnt; j++) { while(now[t].x <= pre[j].y && t < num) { if(now[t].y >= pre[j].x) { now[t].x = max(now[t].x, pre[j].x); } else { now[t].x = -1; now[t].y = -1; } t++; } if(t > num)break; } cnt = 0; for(int j = 0; j < t; j++) { if(now[j].x != -1 && now[j].y != -1) { pre[cnt].x = now[j].x; pre[cnt].y = now[j].y; cnt++; } } if(cnt == 0) return false; i = k; } if(a[m - 1].y != n) return true; if(pre[cnt - 1].y == n) return true; return false; } int main() { scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); a[i].x = x; a[i]. y = y; } sort(a, a + m, cmp); if(check()) printf("%d\n", 2 * n - 2); else puts("-1"); return 0; }
E. Propagating tree
题意:给n(2e5)个数,有两种操作
1 x v 表示给点x加上权值v,在x的子节点中,和x奇偶性相同的加上权值v,奇偶性不同的减去权值v
2 x 表示询问点x的权值是多少
思路:先进行dfs序预处理,建立两颗线段树,如果他在奇数层,就在奇数层+val,偶数层-val,分别插在不同的两棵线段树中,查询直接查询那个数的奇偶性所在的线段树
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 200000 + 7; int tree[2][maxn << 2]; LL lazy[2][maxn << 2]; int n, m; struct node { int nxt, to; }; node Edge[maxn << 2]; int cnt = 0, ti = 0; int head[maxn]; int dep[maxn], a[maxn]; int in[maxn], out[maxn]; void addedge(int u, int v) { Edge[cnt].to = v; Edge[cnt].nxt = head[u]; head[u] = cnt++; } void dfs(int now, int pre) { dep[now] = dep[pre] + 1; in[now] = ++ ti; for(int i = head[now]; ~i; i = Edge[i].nxt) { int v = Edge[i].to; dfs(v, now); } out[now] = ti; } void pushdown(int rt, int dp, int len) { tree[dp][rt << 1] += lazy[dp][rt] * (len - (len >> 1)); lazy[dp][rt << 1] += lazy[dp][rt]; tree[dp][rt << 1 | 1] += lazy[dp][rt] * (len >> 1); lazy[dp][rt << 1 | 1] += lazy[dp][rt]; lazy[dp][rt] = 0; } void update(int L, int R, int val, int dp, int rt, int l, int r) { if(L <= l && r <= R) { tree[dp][rt] += val; lazy[dp][rt] += val; return ; } if(lazy[dp][rt]) pushdown(rt, dp, r - l + 1); int mid = (l + r) >> 1; if(L <= mid) update(L, R, val, dp, rt << 1, l, mid); if(R > mid) update(L, R, val, dp, rt << 1 | 1, mid + 1, r); } int query(int x, int dp, int rt, int l, int r) { if (l == r) { return tree[dp][rt]; } if(lazy[dp][rt]) pushdown(rt, dp, r - l + 1); int mid = (l + r) >> 1; if(x <= mid) return query(x, dp, rt << 1, l, mid); if(x > mid) return query(x, dp, rt << 1 | 1, mid + 1, r); } int main() { cnt = 0; ti = 0; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = 0; i <= n; i++) head[i] = -1; for(int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v); } dep[0] = 0; dfs(1, 0); for(int i = 1; i <= m; i++) { int op; scanf("%d", &op); if(op == 1) { int x, val; scanf("%d%d", &x, &val); update(in[x], out[x], val, dep[x]&1, 1, 1, n); update(in[x] + 1, out[x], -val, !(dep[x]&1), 1, 1, n); } else { int x; scanf("%d", &x); printf("%d\n",query(in[x], dep[x]&1, 1, 1, n) + a[x]); } } return 0; }