P3586 [POI2015] LOG 题解
维护一个长度为 的序列,一开始都是 ,支持以下两种操作:
- 将序列中第 个数修改为 。
- 在这个序列上,每次选出 个正数,并将它们都减去 ,询问能否进行 次操作。
对于 的数据,,,,
题意比较抽象,解题关键在于理解。
以下对一种可能的序列 进行讨论:
- 如何理解能否进行s次操作。
设存在 个 ,满足 ;存在 个 ,满足 。令 。
-
对于 , 次选择都使用,即最多被使用 次。因为 ,所以只需关注 。
-
对于 ,可以凑一凑,让每个都能被利用上,即凑出 个。(证明请看洛谷题解)。
两种方式共有 种,与 判断大小即可。
- 时间复杂度?
求 ,求 ,显然超时。
可以维护一个升序序列,再用前缀和,使用树状数组优化前缀和。
得单点修改序列 ,求前缀和 。
具体细节见代码。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6+1;
int n,a[N],m,q[N],l1[N],l2[N],cnt,len;
char s[N];
struct tree{
int c[N];
int lowbit(int x) {
return x & -x;
}
void upd(int x,int k) {//将第 x 加 k
for(int i=x;i<=len;i+=lowbit(i)) {
c[i]+=k;
}
}
int s(int x) {
int p=0;
for(int i=x;i;i-=lowbit(i)) {
p+=c[i];
}
return p;
}
}t1,t2;
//t1 维护a次数 ;t2 维护a和
signed main() {
cin>>n>>m;
for(int i=1;i<=m;i++) {
cin>>s[i]>>l1[i]>>l2[i];
if(s[i]=='U')
a[++cnt]=l2[i];
}
sort(a+1,a+cnt+1);
len=unique(a+1,a+cnt+1)-(a+1);//此处去重,方便统计出现次数
for(int i=1;i<=m;i++) {
int wh=lower_bound(a+1,a+len+1,l2[i])-a;
if(s[i]=='U') {
int y=l1[i];
if(q[y]) {
// cout<<i<<"114514";
int wh2=lower_bound(a+1,a+len+1,q[y])-a;
t1.upd(wh2,-1);
t2.upd(wh2,-q[y]);
}
t1.upd(wh,1);
t2.upd(wh,l2[i]);
q[l1[i]]=l2[i];
}
if(s[i]=='Z') {
int bigger=t1.s(len)-t1.s(wh-1);
int smaller=t2.s(wh-1);
printf("%s\n",(bigger+smaller/l2[i]>=l1[i]?"TAK":"NIE"));
}
}
return 0;
}

浙公网安备 33010602011771号