【BZOJ2762】[JLOI2011]不等式组(树状数组)
题目:
分析:
加入的不等式分三种情况
当\(a>0\),可以变成\(x>\lfloor \frac{c-b}{a}\rfloor\)
当\(a=0\),若\(b>c\)则恒成立,否则恒不成立
当\(a<0\),可以变成\(x<\lceil \frac{c-b}{a}\rceil\)
对于\(a=0\),用一个变量\(sum\)记一下当前有多少不等式恒成立,删除的时候注意要维护\(sum\)。
对于\(a\neq0\),可以开两个权值树状数组\(greater\)和\(less\)记录。当加入\(a>0\)时,令\(x=\lfloor \frac{c-b}{a}\rfloor\),给\(greater\)的\(x\)位置加\(1\),查询时查\([0,k)\)区间的和。\(a<0\)时在\(less\)上类似。
对于删除操作,在树状数组上删除该不等式贡献的值即可。注意要记录已删除的不等式防止重复删除。
代码:
这题思路简单,但是代码细节比较多……
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
namespace zyt
{
const int DELETED = 1e9, P = 1e6 + 10, OPT = 1e5 + 10, N = P * 2;
class Tree_Array
{
private:
int data[N];
inline int lowbit(const int x)
{
return x & -x;
}
public:
Tree_Array()
{
memset(data, 0, sizeof(data));
}
inline void add(int a, const int x)
{
while (a < N)
data[a] += x, a += lowbit(a);
}
inline int query(int a)
{
int ans = 0;
while (a > 0)
ans += data[a], a -= lowbit(a);
return ans;
}
}less, greater;
int n;
pair<int, int> opt[OPT];
int cnt, sum;
int work()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
for (int i = 0; i < n; i++)
{
string s;
cin >> s;
if (s == "Add")
{
int a, b, c, x;
cin >> a >> b >> c;
if (a == 0)
{
opt[++cnt] = make_pair(0, (bool)(b > c));
if (b > c)
sum++;
}
else if (a < 0)
{
x = (int)(ceil((c - b) / (double)a) + P);
if (x < 1)
x = 1;
if (x >= N)
x = N - 1;
opt[++cnt] = make_pair(-1, x);
less.add(x, 1);
}
else
{
x = (int)(floor((c - b) / (double)a) + P);
if (x < 1)
x = 1;
if (x >= N)
x = N - 1;
opt[++cnt] = make_pair(1, x);
greater.add(x, 1);
}
}
else if (s == "Del")
{
int a;
cin >> a;
if (opt[a].first == 0)
sum -= (opt[a].second == 1);
else if (opt[a].second != DELETED)
{
if (opt[a].first == -1)
less.add(opt[a].second, -1);
else
greater.add(opt[a].second, -1);
}
opt[a].second = DELETED;
}
else
{
int a;
cin >> a;
a += P;
cout << sum + greater.query(a - 1) + less.query(N - 1) - less.query(a) << '\n';
}
}
return 0;
}
}
int main()
{
return zyt::work();
}