Store
time limit per test 1.0 s
memory limit per test 256 MB
题目链接http://whu2019.contest.codeforces.com/group/YyBKO8xFiH/contest/102167/problem/C
题目大意:lc是一个商店的店主,他现在想要确定已经卖出货物的比给定值K大的最小值。给你k的最大值n,和q次操作,M x,y,表示第x天卖出数量为y的商品,D x,y,表示询问在x天以前(含x)有没有卖出的商品数量大于等于y,如果有输出大于等于y的最小值,否则输出-1。
一看到题目就基本上想得到线段树,但我们的线段树要以什么为基础建立呢?仔细想一下也无非就两种情况,按照x(天数),按照y(数量)。但x的值可达到1e9,所以不做考虑。那么也就是说我们线段树的1到n的序号就是y的有序排列,要找比y大的,我们只需要在y到n的区间查找就ok了。
接下来就是解决天数小于x。之前我们已经建好了一颗空树,那么我们就应该在里面存些数据,不用想也知道要存x,但我们的底层存了x,他们的上层呢?由于需要天数小于x的,那么我们就存x的最小值。于是就变成了区间查找最小值了。
下一个问题就是我们可以用线段树查找在数量y-n之间是否有满足条件的,但我们无法确定到底是哪个单点满足,就更别说要寻找到y-n的最小值满足了。那么把这个问题单独提出来我们就应该很容易发现可以用二分答案。我们二分y-n,对于每一次的二分,我们对于区间y-mid询问是否满足条件,如果满足,我们就压缩n,否则y=mid。然后这道题就结束了。。。。
以下是详细代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int mac=2e5+10;
const int inf=1e9+500;
using namespace std;
struct node
{
int l,r,mi;
}tree[mac*4];
int mid,mark=0,ans=inf,p=inf,r,k,lr;
void build(int now,int l,int r);
void change_pot(int now);
void ask(int now);
int main()
{
int n,q;
scanf ("%d%d",&n,&q);
build(1,1,mac);
for (int i=1; i<=q; i++){
char ch=getchar();
while (ch!='D' && ch!='M') ch=getchar();
if (ch=='M'){
scanf ("%d%d",&k,&r);
change_pot(1);
}
else if (ch=='D'){
scanf ("%d%d",&k,&lr);
ans=inf;
int ll=lr,rr=mac;
for (int j=1; j<=20; j++){
p=inf;
mid=(ll+rr)>>1;//以mid为右边界,k为左边界
mark=0;
ask(1);
if (mark){
ans=mid;rr=mid;
}
else ll=mid;
}
if (ans==inf) printf ("-1\n");
else printf ("%d\n",ans);
}
}
return 0;
}
void build(int now,int l,int r)
{
tree[now].r=r,tree[now].l=l;
if (l==r){
tree[now].mi=inf;
return;
}
int mid1=(l+r)>>1;
build (now*2,l,mid1);
build (now*2+1,mid1+1,r);
tree[now].mi=inf;
}
void change_pot(int now)
{
if (tree[now].l==tree[now].r){
tree[now].mi=k;
return;
}
int mid1=(tree[now].l+tree[now].r)>>1;
if (r<=mid1) change_pot(now*2);
else change_pot(now*2+1);
tree[now].mi=min(tree[now*2+1].mi,tree[now*2].mi);
}
void ask(int now)
{
if (mark) return;
if (tree[now].l>=lr && tree[now].r<=mid){
p=min(p,tree[now].mi);
if (p<=k) {
mark=1;
}
return;
}
int mid1=(tree[now].l+tree[now].r)>>1;
if (lr<=mid1) ask(now*2);
if (mid>mid1) ask(now*2+1);
}