题意描述 给出 $n$ 次操作,每次操作是下列的一种:
添加一条形如 $ax + b > c$ 的不等式
删除其中一条不等式
询问当 $x = k$ 时成立的不等式的个数
请快速处理以上操作并输出相应的结果。
输入格式 第一行为一个正整数 $n$,代表接下来有 $n$ 行。
接下来每一行可能有 $3$ 种形式:
Add a b c
:表明要往不等式组添加一条不等式 $ax+b>c$。
Del i
:代表删除掉第 $i$ 条添加的不等式(最先添加的是第 $1$ 条)。
Query k
:代表一个询问,即当 $x=k$ 时,在当前不等式组内成立的不等式的数量。
注意:一开始不等式组为空,$a,b,c,i,k$ 均为整数,且保证所有操作均合法,不会出现要求删除尚未添加的不等式的情况。
输出格式 对于每一个询问 Query k
,输出一行一个整数,代表询问的答案。
9 Add 1 1 1 Add -2 4 3 Query 0 Del 1 Query 0 Del 2 Query 0 Add 8 9 100 Query 10
Output ‘s eg
数据范围和约定 对于 $20\%$ 的数据,保证 $n\leq 10^3$。
对于 $40\%$ 的数据,保证 $n\leq 10^4$。
对于 $100\%$ 的数据,保证 $1\leq n\leq 10^5$ ,$a,b,c \in \lbrack -10^8,10^8 \rbrack$,$k\in \lbrack-10^6,10^6 \rbrack$。
分析 直接带入维护并不好维护,考虑移项。
对于不等式 $ax + b > c$ ,移项之后有以下三种情况:
$a = 0$,移项后成了 $b > c$。这种情况要么恒成立要么永远不成立,特判即可
$a > 0$,移项后成了 $x > \lceil \frac{c - b}{a} \rceil$。
$a < 0$,移项后成了 $x < \lfloor \frac{c - b}{a} \rfloor$。
对于情况 $2$ 和情况 $3$,我们各开一个树状数组维护区间内大于或小于某个数的个数 即可。
设 $t1$ 维护 $a > 0$ 的情况 , $t2$ 维护 $a < 0$ 的情况 ,则查询 $x = k$ 的答案即为
其中,$cnt$ 为恒成立的不等式的数目。
单次操作的时间复杂度均为 $O(\log k)$,总时间复杂度为 $O(n \log k)$。足以通过本题。
细节部分将在代码注释中呈现,建议仔细参考。
Code[Accepted] #include <algorithm> #include <iostream> #include <cstring> #include <iomanip> #include <cstdlib> #include <climits> #include <cstdio> #include <bitset> #include <string> #include <vector> #include <cctype> #include <stack> #include <queue> #include <deque> #include <cmath> #include <map> #include <set> #define I inline #define fi first #define se second #define pb push_back #define MP make_pair #define PII pair<int , int> #define PSL pair<string , long long> #define PLL pair<long long , long long> #define all(x) (x).begin() , (x).end() #define copy(a , b) memcpy(a , b , sizeof(b)) #define clean(a , b) memset(a , b , sizeof(a)) #define rep(i , l , r) for (int i = (l); i <= (r); i ++) #define per(i , r , l) for (int i = (r); i >= (l); i --) #define PE(i , x) for(int i = head[x]; i; i = edge[i].last) #define DEBUG(x) std :: cerr << #x << '=' << x << std :: endl typedef long long ll;typedef unsigned long long ull;template <class T >inline void read (T &x) { char c = getchar(), f = 0 ; x = 0 ; while (!isdigit (c)) f = (c == '-' ), c = getchar(); while (isdigit (c)) x = x * 10 + c - '0' , c = getchar(); x = f ? -x : x; } using namespace std ;const int N = 10000 + 5 ;const int M = 1000000 + 5 ;const int HA = 998244353 ;int tree1[M << 1 ] , tree2[M << 1 ] , lim = (M << 1 );int lowbit (int x) { return x & (-x); }void add (int x , int val , int tree[]) { x += M; for (int i = x; i <= lim; i += lowbit(i)){ tree[i] += val; } } int query (int x , int tree[]) { x += M; int ans = 0 ; for (int i = x; i ; i -= lowbit(i)){ ans += tree[i]; } return ans; } int type[M << 1 ] , tk[M << 1 ] , tot , cnt; void insert () { int a , b , c; read(a) , read(b) , read(c); if (a == 0 ){ if (b > c){ cnt ++ , type[++ tot] = (1 << 30 ); } else { type[++ tot] = -(1 << 30 ); } } else if (a < 0 ){ tk[++ tot] = (ceil )((1.0 * c - b) / a); type[tot] = 2 ; if (tk[tot] > (int )1e6 ){ cnt ++ , type[tot] = (1 << 30 ); } else if (tk[tot] < (int )-1e6 ){ type[tot] = -(1 << 30 ); } else { add(tk[tot] , 1 , tree2); } } else if (a > 0 ){ tk[++ tot] = (floor )((1.0 * c - b) / a); type[tot] = 1 ; if (tk[tot] > (int )1e6 ){ type[tot] = -(1 << 30 ); } else if (tk[tot] < (int )-1e6 ){ cnt ++ , type[tot] = (1 << 30 ); } else { add(tk[tot] , 1 , tree1); } } } int del[M << 1 ];void Delete () { int k; read(k); if (del[k]) return ; del[k] = 1 ; if (type[k] == (1 << 30 )) cnt --; else if (type[k] == 1 ){ add(tk[k] , -1 , tree1); } else if (type[k] == 2 ){ add(tk[k] , -1 , tree2); } } int Query () { int x; read(x); return cnt + query(x - 1 , tree1) + query((int )1e6 , tree2) - query(x , tree2); } int main () { #ifdef LOCAL freopen("try.in" , "r" , stdin ); freopen("try1.out" , "w" , stdout ); #endif int n; read(n); char op[10 ]; while (n --){ scanf ("%s" , op + 1 ); if (op[1 ] == 'A' ){ insert(); } else if (op[1 ] == 'D' ){ Delete(); } else if (op[1 ] == 'Q' ){ printf ("%d\n" , Query()); } } return 0 ; }
THE END