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

浙公网安备 33010602011771号