买礼物
线段树+双向链表
一组长度为n的序列,每个数都在1-n
给定操作
操作一:删除区间的某个元素
操作二:给定区间l,r,问区间内是否有相同的元素
如果暴力做的的话,对于区间(L,R),遍历每个元素,找他后面有没有和他相同的元素,单次操作的复杂度是平方级别的。
这题需要进行适当的转换。
找某个元素后面和他相同的元素,可以转换为链表的形式,每个链表的next指针指向和他相同的元素的位置。 则对next指针建立线段树,每次查询区间内的最小值,观察最小值是否落在(L,R)。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 5e5 + 10;
int pre[N], ne[N], pos[N];
struct Node
{
int l, r, v;
}tr[4 * N];
void pushup(int u)
{
tr[u].v = min(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r)
{
if (l == r)
tr[u] = {l, r, ne[l]};
else
{
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int v)
{
if (tr[u].l == tr[u].r)
{
tr[u].v = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
int query(int u, int l, int r)
{
if (l <= tr[u].l && tr[u].r <= r)
return tr[u].v;
int mid = tr[u].l + tr[u].r >> 1;
int v = N;
if (l <= mid) v = min(v, query(u << 1, l, r));
if (r > mid) v = min(v, query(u << 1 | 1, l, r));
return v;
}
int main()
{
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i ++)
ne[i] = N;
for (int i = 1; i <= n; i ++)
{
int c;
cin >> c;
ne[pos[c]] = i;
pre[i] = pos[c];
pos[c] = i;
}
ne[n] = N;
build(1, 1, n);
while(q --)
{
int m, a, b;
cin >> m;
if (m == 1)
{
cin >> a;
ne[pre[a]] = ne[a];
pre[ne[a]] = pre[a];
modify(1, pre[a], ne[a]);
modify(1, a, N);
}
else
{
cin >> a >> b;
int v = query(1, a, b);
// cout << "---" << v << endl;
if (a <= v && v <= b)
puts("1");
else puts("0");
}
}
}
超市
贪心+并查集
大致意思:超市里有N件商品,每件商品都有利润pi和过期时间di,每天只能卖一件商品,过期商品不能再卖。
如何安排每天卖的商品的情况下,可以得到的最大收益是多少。
考虑贪心方案:先对利润从大到小排序,然后遍历商品,对于一件商品,尽量在最接近过期时间的点出售。因此朴素做法是每遍历到一件商品,搜索他的卖出的最接近过期时间的点。时间复杂度是平方的。
考虑用并查集优化搜索。
可以将所有日期建立成并查集,日期记录他最近的前面的空闲日期是哪天,初始时全都指向自己。在某个日期卖出商品时,就把这个日期表示的位置指向前一个位置,表示此日期已经被占用。这样每次搜索时,路径压缩 能在logn时间内找出空闲的日期。
#include <queue>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e4 + 10;
typedef pair<int, int> PII;
PII cmd[N];
int n, p, d;
int fa[N];
void init(int n)
{
for (int i = 0; i <= n; i ++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
while (cin >> n)
{
init(10000);
int res = 0;
for (int i = 0; i < n; i ++)
{
cin >> p >> d;
cmd[i] = {p, d};
}
sort(cmd, cmd + n);
for (int i = n - 1; i >= 0; i --)
{
int px = cmd[i].first;
int pd = cmd[i].second;
int deadline = find(pd);
// printf("---px:%d---pd:%d-----deadline:%d\n", px, pd, deadline);
if (deadline != 0)
{
res += px;
fa[deadline] = deadline - 1;
}
}
cout << res << endl;
}
}