洛谷P4396 [AHOI2013]作业 主席树+莫队套数据结构
洛谷P4396 [AHOI2013]作业
标签
- 主席树
- 莫队套数据结构
前言
- 我的csdn和博客园是同步的,欢迎来访danzh-博客园~
简明题意
- 给定一个序列,需要支持两种查询操作:
- 查询区间[l,r]中权值位于[a,b]的数的个数
- 查询区间[l,r]中权值位于[a,b]的权值种数
思路
- 第一问直接主席树吧~(如果不卡空间)
- 第二问其实是个莫队套数据结构的经典题目了。可以莫队套分块复杂度优秀些,莫队套权值线段树卡卡常应该也能过~具体可以看看这篇博客戳这里,那一题跟这题一样的,就是数据范围大了10倍。
注意事项
- 主席树别写炸了惹
总结
- 无
AC代码
#include<cstdio>
#include<cmath>
#include<bitset>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int pos[maxn];
struct Query
{
int l, r, a, b, id;
bool operator < (const Query& a)const
{
if (pos[l] == pos[a.l])
return r < a.r;
return pos[l] < pos[a.l];
}
}; Query query[maxn];
struct Node
{
Node* lson;
Node* rson;
int l, r, sum;
Node(int l, int r, int sum = 0)
{
lson = rson = NULL;
this->l = l, this->r = r;
this->sum = sum;
}
}; Node* tree[maxn];
Node* build(Node* o, int l, int r)
{
o = new Node(l, r);
if (l == r)
return o;
int mid = (l + r) / 2;
o->lson = build(o->lson, l, mid);
o->rson = build(o->rson, mid + 1, r);
return o;
}
Node* change(Node* o, Node* laso, int k)//添加权值k
{
o = new Node(*laso); o->sum++;
if (o->l == o->r)
return o;
int mid = (o->l + o->r) / 2;
if (k <= mid)//改左子树,连右子树
{
o->rson = laso->rson;
o->lson = change(o->lson, laso->lson, k);
}
else
{
o->lson = laso->lson;
o->rson = change(o->rson, laso->rson, k);
}
return o;
}
int ask(Node* L, Node* R, int l, int r)
{
if (l == L->l && r == L->r)
return R->sum - L->sum;
int mid = (L->l + L->r) / 2;
if (r <= mid)
return ask(L->lson, R->lson, l, r);
else if (l > mid)
return ask(L->rson, R->rson, l, r);
else
return ask(L->lson, R->lson, l, mid) + ask(L->rson, R->rson, mid + 1, r);
}
int n, q, a[maxn], len;
struct FK
{
int cnt[maxn], b[maxn];
void change(int x, int type)
{
cnt[a[x]] += type;
b[pos[a[x]]] += type;
}
int ask(int l, int r)
{
int ans = 0;
for (int i = l; i <= min(pos[l] * len, r); i++)
ans += cnt[i];
if (pos[l] != pos[r])
for (int i = pos[r] * len - len + 1; i <= r; i++)
ans += cnt[i];
for (int i = pos[l] + 1; i <= pos[r] - 1; i++)
ans += b[i];
return ans;
}
}; FK fk;
int cnt[maxn];
void remove(int id)
{
if (cnt[a[id]]-- == 1)
fk.change(id, -1);
}
void add(int id)
{
if (cnt[a[id]]++ == 0)
fk.change(id, 1);
}
pair<int, int> ans0[maxn];
void solve()
{
tree[0] = build(tree[0], 1, maxn - 10);
scanf("%d%d", &n, &q);
len = sqrt(n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), pos[i] = (i - 1) / len + 1;
for (int i = 1; i <= q; i++)
scanf("%d%d%d%d", &query[i].l, &query[i].r, &query[i].a, &query[i].b), query[i].id = i;
sort(query + 1, query + 1 + q);
for (int i = 1; i <= n; i++)
tree[i] = change(tree[i], tree[i - 1], a[i]);
int l = 1, r = 0;
for (int i = 1; i <= q; i++)
{
int L = query[i].l, R = query[i].r, a = query[i].a, b = query[i].b, id = query[i].id;
while (l < L) remove(l++);
while (l > L) add(--l);
while (r < R) add(++r);
while (r > R) remove(r--);
ans0[id].second = ask(tree[L - 1], tree[R], a, b);
ans0[id].first = fk.ask(a, b);
}
for (int i = 1; i <= q; i++)
printf("%d %d\n", ans0[i].second, ans0[i].first);
}
int main()
{
freopen("Testin.txt", "r", stdin);
solve();
return 0;
}
作者:danzh
QQ:1244536605
CSDN(和博客园同步):https://blog.csdn.net/weixin_42431507
-----------------------------------------------------------------------------------------------
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其
它人怎么样,我们也能够保持自己的本色走下去。
—clj