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;
}
View Code

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;
}
View Code

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;
}
View Code

 

posted @ 2019-02-25 18:51  啦啦啦天啦噜  阅读(242)  评论(0编辑  收藏  举报