Luogu_P3586_POI2015_LOG
树状数组 yyds#
题意#
给定一个序列,支持两种操作:
- 修改: 把第 个数字改为
- 查询: 是否可以找到 个大于 的数字,并把他们都减去 , 执行 次
注: 每次查询不影响原序列的值
Trick#
对于查询来说,如果某个数字的个数 ,那么这个数字就可以执行 次 减去 的操作,那么我们每此选出的 个数字都都可以有
假设这样的数字有 个,那么我们只需要在 个数 的数字之中选择,满足每此找到 个数字 把他们减去 , 执行 次
经过证明可以得知,如果这样的数字的个数是 那么我们就可以执行这个操作 次。
实现#
我们可以先离散化一下,然后用两个树状数组,一个维护有多少种数字,另一个维护数字的个数
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");
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现