Luogu_P3586_POI2015_LOG
树状数组 yyds
题意
给定一个序列,支持两种操作:
- 修改: 把第 \(k\) 个数字改为 \(x\)
- 查询: 是否可以找到 \(c\) 个大于 \(1\) 的数字,并把他们都减去 \(1\), 执行 \(k\) 次
注: 每次查询不影响原序列的值
Trick
对于查询来说,如果某个数字的个数 \(X \ge k\) ,那么这个数字就可以执行 \(k\) 次 减去 \(1\) 的操作,那么我们每此选出的 \(c\) 个数字都都可以有 \(X\)
假设这样的数字有 \(cnt\) 个,那么我们只需要在 个数 $ < k$ 的数字之中选择,满足每此找到 \(c - cnt\) 个数字 把他们减去 \(1\), 执行 \(k\) 次
经过证明可以得知,如果这样的数字的个数是 \(CNT \ge (c - cnt) * k\) 那么我们就可以执行这个操作 \(k\) 次。
实现
我们可以先离散化一下,然后用两个树状数组,一个维护有多少种数字,另一个维护数字的个数
Solution
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define leng(a) (int)a.size()
#define lowbit(x) (x&-x)
#define fix(a) fixed << setprecision(a)
#define debug(x) cout<<#x" ----> "<<x<<endl
#define rep(i, b, s) for(int i = (b); i <= (s); ++i)
#define pre(i, b, s) for(int i = (b); i >= (s); --i)
#define TEST int T; read(T); while(T --)
//#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
#define all(v) (v).begin(),(v).end()
using namespace std;
typedef unsigned long long ULL;
typedef pair<int, int> PII ;
typedef pair<int, PII> PIII ;// {value, {value, value}}
typedef pair<double, double> PDD ;
typedef long long LL;
const int INF = INT_MAX;
const LL INFF = INT64_MAX;
const int MOD = 998244353;
const double eps = 1e-10;
const double pi = acos(-1.0);
LL gcd(LL a, LL b) {return b ? gcd(b, a%b) : a;}
inline LL ksm(LL a, LL b) {if (b == 0) return 1; LL ns = ksm(a, b >> 1); ns = ns * ns % MOD; if (b & 1) ns = ns * a % MOD; return ns;}
inline LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
inline void out(bool flag);
template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
template <typename T> inline T mod(T &x) {return x % MOD;}
inline bool valid(char c) { return 33<=c&&c<=126; }
template < typename T >
inline void read(T &x)
{
x = 0; bool f = 0; char ch = getchar();
while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
x = f ? -x : x;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
{ read(x),read(args...); }
inline void reads(char *s) {
int l=0;char c;
while(!valid(s[0]=getchar()));
while(valid(s[++l]=getchar()));
}
int n, m;
const int N = 2e6 + 10;
int a[N];
LL tr[N][2];
int op[N];
PII query[N];
int mx;
vector<int> ALL;
void add(int a, int b, int id) {
while(a <= mx) {
tr[a][id] += b;
a += lowbit(a);
}
}
LL sum(int a, int id) {
LL res = 0;
while(a) {
res += tr[a][id];
a -= lowbit(a);
}
return res;
}
inline void solve() {
read(n, m);
rep(i, 1, m) {
char OP[3];
reads(OP);
int X, Y; read(X, Y);
query[i] = {X, Y};
if(*OP == 'U') op[i] = 1;
else op[i] = 2;
ALL.pb(X); ALL.pb(Y);
}
sort(all(ALL));
ALL.erase(unique(all(ALL)), ALL.end());
mx = ALL.size();
function <int(int)> find = [&] (int x) { return lower_bound(all(ALL), x) - ALL.begin() + 1;};
rep(i, 1, m) {
int id = op[i];
int l = query[i].fi, r = query[i].se;
int L = find(l), R = find(r);
// tr[][0] 代表的是个数
// tr[][1] 代表的是和
// 我们需要的是 >= R 的数字的个数 以及 < R 的数字的和
if(id == 1) {
int last = a[L];
int res = find(last);
if(last > 0)
add(res, -1, 0), add(res, -last, 1);
if(r > 0)
add(R, 1, 0), add(R, r, 1);
a[L] = r;
} else {
int cnt = sum(mx, 0) - sum(R - 1, 0);
if(cnt >= l) puts("TAK");
else {
LL ans = sum(R - 1, 1);
if(1LL * (l - cnt) * r <= ans) puts("TAK");
else puts("NIE");
}
}
}
}
signed main()
{
solve();
return 0;
}
inline void out(bool flag) {
if(flag) puts("YES");
else puts("NO");
}