20231127

2023/11/27

Codeforces Round 882 (Div. 2)

题解:

A.

分成m段,也就是有m-1段的绝对值不用算。那么我们让总和最小,肯定是让前m-1段最大的不用算

B

根据位运算&的性质,前缀与是会越来越小的. 如果一个数组的&值不为0,说明在二进制的某一位上大家都为1.这个时候再分成两段,一定会让和变大.所以只能有1段. 如果为0,那么我们贪心去找,一旦有一段的&为0, 那么立即截断.因为再加一个数也是0,不如让这个数去跟下一段& ,更有可能为0.

C

赛时思路和结论完全ok,只是忘记怎么写这个经典问题了。

求一个连续子数组的最大异或和: 用字典树,扫一遍数组,一次往Trie树里面加入前缀异或和。然后对于当前这个异或值,我们去字典树里面找跟他异或起来最大的(本质就是最大异或对),套了一个前缀

Trie树清空记得从0 开始, 把0~idx清空就行

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
int n, m, idx;
const int N = 1e6 + 10;
int a[N];
int son[N][2];

void insert(int x)
{
    int p = 0;
    for (int i = 8; i >= 0; i--)
    {
        int id = ((x >> i) & 1);
        if (!son[p][id])
        {
            son[p][id] = ++idx;
        }
        p = son[p][id];
    }
}

int query(int x)
{
    int p = 0, res = 0;
    for (int i = 8; i >= 0; i--)
    {
        int id = ((x >> i) & 1);
        if (son[p][!id])
        {
            res += (1LL << i);
            p = son[p][!id];
        }
        else
            p = son[p][id];
    }
    return res;
}

void solve()
{
    for (int i = 0; i <= idx; i++)
    {
        son[i][1] = son[i][0] = 0;
    }
    idx = 0;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int res = 0;
    insert(0LL);
    int ans = 0;
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        cnt ^= a[i];
        ans = max(ans, query(cnt));
        insert(cnt);
    }
    cout << ans << endl;
}

signed main()
{
    Acode;
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

扫描线-矩形面积并

建树的时候,叶子节点也是代表了一段区间而不是一个数,其实合并时一样的,只是build初始化的时候cnt要处理一下。因为build(1,1,m)里的m代表的是区间个数,所以这里的区间会比点数少一

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
int n, m, idx;
const int N = 1e6 + 10;
int a[N];

struct info
{
    int minv, cnt;
};

struct node
{
    info val;
    int lazy;
} seg[N << 2];

vector<array<int, 4>> evt;
vector<int> alls;
int find(int x)
{
    return lower_bound(alls.begin(), alls.end(), x) - alls.begin();
}

info operator+(const info &a, const info &b)
{
    info c;
    if (a.minv < b.minv)
    {
        c.cnt = a.cnt;
        c.minv = a.minv;
    }
    else if (a.minv > b.minv)
    {
        c.cnt = b.cnt;
        c.minv = b.minv;
    }
    else
    {
        c.cnt = a.cnt + b.cnt;
        c.minv = a.minv;
    }
    return c;
}

void up(int id)
{
    seg[id].val = seg[id << 1].val + seg[id << 1 | 1].val;
}

void build(int id, int l, int r)  // 建树的时候,叶子节点代表往前的一段区间
{
    seg[id].lazy = 0;
    if (l == r)
    {
        seg[id].val.minv = 0;
        seg[id].val.cnt = alls[l] - alls[l - 1];
        return;
    }
    int mid = l + r >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    up(id);
}

void settag(int id, int val)
{
    seg[id].val.minv += val;
    seg[id].lazy += val;
}

void down(int id)
{
    if (!seg[id].lazy)
        return;
    settag(id << 1, seg[id].lazy);
    settag(id << 1 | 1, seg[id].lazy);
    seg[id].lazy = 0;
}

void modify(int id, int l, int r, int ql, int qr, int val)
{
    if (l > qr || r < ql)
        return;
    if (ql <= l && r <= qr)
    {
        settag(id, val);
        return;
    }
    down(id);
    int mid = l + r >> 1;
    modify(id << 1, l, mid, ql, qr, val);
    modify(id << 1 | 1, mid + 1, r, ql, qr, val);
    up(id);
}

info query(int id, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return seg[id].val;
    int mid = l + r >> 1;
    down(id);
    if (qr <= mid)
        return query(id << 1, l, mid, ql, qr);
    else if (ql > mid)
        return query(id << 1 | 1, mid + 1, r, ql, qr);
    else
        return query(id << 1, l, mid, ql, qr) + query(id << 1 | 1, mid + 1, r, ql, qr);
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        alls.push_back(y1);
        alls.push_back(y2);
        evt.push_back({x1, 1, y1, y2});
        evt.push_back({x2, -1, y1, y2});
    }
    sort(evt.begin(), evt.end());
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());
    int m = alls.size() - 1;  //区间个数会比点少一个
    build(1, 1, m);
    int len = query(1, 1, m, 1, m).cnt;
    int ans = 0;
    int pre = evt[0][0];
    modify(1, 1, m, find(evt[0][2]) + 1, find(evt[0][3]), evt[0][1]);
    for (int i = 1; i < evt.size(); i++)
    {
        int x = evt[i][0];
        int id = evt[i][1];
        int y1 = evt[i][2];
        int y2 = evt[i][3];
        int res = query(1, 1, m, 1, m).minv;
        int cnt = query(1, 1, m, 1, m).cnt;
        if (!res)
        {
            ans += (x - pre) * (len - cnt);
        }
        else
            ans += (x - pre) * len;
        int pos1 = find(y1) + 1;  // 用l+1这个点表示[l, l + 1]这段长度
        int pos2 = find(y2);
        if (id == 1)
            modify(1, 1, m, pos1, pos2, 1);
        else
            modify(1, 1, m, pos1, pos2, -1);
        pre = x;
    }
    cout << ans << endl;
}

signed main()
{
    Acode;
    int T = 1;
    // cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}
posted @ 2023-11-28 00:50  ヤ﹎句号悠灬  阅读(26)  评论(0)    收藏  举报