2020牛客暑期多校训练营(第二场)[Happy Triangle]
2020牛客暑期多校训练营(第二场)Happy Triangle
题目大意:
给你m次操作,每次操作两个数,\(opt\) 和 \(x\) ,\(opt\) 有三种取值情况,
- \(opt==1\) 表示把 \(x\) 放入数组
- \(opt==2\) 表示把 \(x\) 移除
- \(opt==3\) 表示查询 \(x\) 是不是数组中存在 $ a 、 b$ 使得 \(x、a、b\) 可以构成一个三角形
题解:
题目不是很难想,但是写起来感觉还是比较复杂的。。。
第一第二个很好用线段树维护,第三个线段树就要维护一段区间的两个数的和最大和两个数的差最小。
-
差最小,表示的是当前的 \(x\) 是最小值,所以要有解的话,就是最大值减去次大值要小于这个最小值即可,是要求后面的一段区间,所以在线段是位置 \(i\) 维护的是 \(i\) 到末尾的数字的差值最小。
这个怎么维护呢,首先线段树+二分可以求出大于等于这个位置的最小值,求出来之后,直接用这个值 \(val-x\) 插入线段树位置 \(i\)
-
然后就是和最大,表示的是当前的 \(x\) 是最大值,所以要有解,那么就是最大值要小于次大值+最小值,这个是要求前面一段区间,所以同理,线段树+二分求出前面一段区间的最大值,然后 \(val+x\) 插入线段树位置 \(i\)
-
最后就是这个值是中间大小的值,那就是用前面的可以找到了。
最后写的时候觉得用二分比较麻烦,于是就直接把这个值放入了线段树里面,直接线段树查询就可以了。
总的来说,还是写的比较复杂的。。。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define debug(x) printf("debug:%s=%d\n",#x,x);
//#define debug(x) cout << #x << ": " << x << endl
using namespace std;
const int maxn = 2e5+10;
int mins[maxn*4],maxs[maxn*4],a[maxn],v[maxn],opt[maxn];
int Min[maxn*4],Max[maxn*4],num[maxn*4],len;
int MAX(int x,int y){
if(x&&y) return v[x]>v[y]?x:y;
if(x) return x;
if(y) return y;
return 0;
}
int MIN(int x,int y){
if(x&&y) return v[x]>v[y]?y:x;
if(x) return x;
if(y) return y;
return 0;
}
void push_up(int id){
// debug("xxx");
num[id]=max(num[id<<1],num[id<<1|1]);
Min[id]=MIN(Min[id<<1],Min[id<<1|1]);
Max[id]=MAX(Max[id<<1],Max[id<<1|1]);
// debug(id)
// debug(Min[id])
// debug(Max[id])
mins[id]=min(mins[id<<1],mins[id<<1|1]);
maxs[id]=max(maxs[id<<1],maxs[id<<1|1]);
// debug(mins[id]);
// debug(maxs[id]);
// debug(mins[id<<1]);
// debug(mins[id<<1|1]);
}
void update(int id,int l,int r,int pos,int f){
// printf("id=%d l=%d r=%d pos=%d\n",id,l,r,pos);
if(l==r){
if(f) {
if(!num[id]) Min[id]=l,Max[id]=l;
num[id]++;
}
else{
num[id]--;
if(!num[id]) Min[id]=0,Max[id]=0;
}
// debug("sss");
return;
}
int mid=(l+r)>>1;
if(pos<=mid) update(id<<1,l,mid,pos,f);
else update(id<<1|1,mid+1,r,pos,f);
// debug(id)
push_up(id);
}
int query_min(int id,int l,int r,int x,int y){
// printf("id = %d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
if(y<l||x>r) return 0;
if(x<=l&&y>=r) {
return Min[id];
}
int mid=(l+r)>>1,ans=0;
if(x<=mid) ans=MIN(ans,query_min(id<<1,l,mid,x,y));
if(y>mid) ans=MIN(ans,query_min(id<<1|1,mid+1,r,x,y));
return ans;
}
int query_max(int id,int l,int r,int x,int y){
// printf("query_max id=%d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
if(y<l||x>r) return 0;
if(x<=l&&y>=r) {
// debug(Max[id])
return Max[id];
}
int mid=(l+r)>>1,ans=0;
if(x<=mid) ans=MAX(ans,query_max(id<<1,l,mid,x,y));
if(y>mid) ans=MAX(ans,query_max(id<<1|1,mid+1,r,x,y));
return ans;
}
void modify_max(int id,int l,int r,int pos,int val,int f){
// printf("ss id=%d l=%d r=%d pos=%d val=%d f=%d\n",id,l,r,pos,val,f);
if(pos<l||pos>r) return ;
if(l==r){
if(f) maxs[id]=max(maxs[id],val);
else maxs[id]=val;
// debug(maxs[id]);
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) modify_max(id<<1,l,mid,pos,val,f);
else modify_max(id<<1|1,mid+1,r,pos,val,f);
push_up(id);
}
void modify_min(int id,int l,int r,int pos,int val,int f){
if(pos<l||pos>r) return ;
if(l==r){
if(f) mins[id]=min(mins[id],val);
else mins[id]=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) modify_min(id<<1,l,mid,pos,val,f);
else modify_min(id<<1|1,mid+1,r,pos,val,f);
push_up(id);
}
int query(int id,int l,int r,int pos){
if(l==r) return num[id];
int mid=(l+r)>>1;
if(pos<=mid) return query(id<<1,l,mid,pos);
else return query(id<<1|1,mid+1,r,pos);
}
int queryMin(int id,int l,int r,int x,int y){
// printf("id=%d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
if(y<l||x>r) return inf;
if(x<=l&&y>=r) {
return mins[id];
}
int mid=(l+r)>>1,ans=inf;
if(x<=mid) ans=min(ans,queryMin(id<<1,l,mid,x,y));
if(y>mid) ans=min(ans,queryMin(id<<1|1,mid+1,r,x,y));
return ans;
}
int queryMax(int id,int l,int r,int x,int y){
// printf("Max id=%d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
if(y<l||x>r) return 0;
if(x<=l&&y>=r) {
// debug(maxs[id])
return maxs[id];
}
int mid=(l+r)>>1,ans=0;
if(x<=mid) ans=max(ans,queryMax(id<<1,l,mid,x,y));
if(y>mid) ans=max(ans,queryMax(id<<1|1,mid+1,r,x,y));
return ans;
}
int main(){
int m;
scanf("%d",&m);
memset(Min,0,sizeof(Min));
memset(Max,0,sizeof(Max));
memset(mins,inf,sizeof(mins));
memset(maxs,0xef,sizeof(maxs));
// printf("%d %d\n",maxs[0],mins[0]);
for(int i=1;i<=m;i++){
scanf("%d%d",&opt[i],&a[i]);
v[i]=a[i];
}
sort(v+1,v+1+m);
len = unique(v+1,v+1+m)-v-1;
for(int i=1;i<=m;i++){
int t=lower_bound(v+1,v+1+len,a[i])-v;
// debug(a[i]);
// debug(t);
if(opt[i]==1) {
int r = query_min(1,1,len,t,len);
// debug(r);
//r>=t
if(r<=len&&r>=1){
modify_min(1,1,len,t,v[r]-v[t],1);
modify_max(1,1,len,r,v[r]+v[t],1);
}
int l = query_max(1,1,len,1,t);
// debug(l);
//l<=t
if(l<=len&&l>=1){
// debug(v[t]);
// debug(v[l]);
modify_min(1,1,len,l,v[t]-v[l],1);
modify_max(1,1,len,t,v[t]+v[l],1);
}
update(1,1,len,t,1);
}
else if(opt[i]==2) {
// debug("second")
update(1,1,len,t,0);
int cur = query(1,1,len,t);
int r = query_min(1,1,len,t+1,len);
int l = query_max(1,1,len,1,t-1);
// debug(r)
// debug(l)
if(cur==1){
if(r) modify_min(1,1,len,t,v[r]-v[t],0);
else modify_min(1,1,len,t,inf,0);
if(l) modify_max(1,1,len,t,v[l]+v[t],0);
else modify_max(1,1,len,t,-inf,0);
}
else if(cur==0){
modify_min(1,1,len,t,inf,0);
modify_max(1,1,len,t,-inf,0);
if(r) {
int x = query(1,1,len,r);
if(x>=2);
else if(l) modify_max(1,1,len,r,v[l]+v[r],0);
else modify_max(1,1,len,r,-inf,0);
}
if(l) {
int x = query(1,1,len,l);
if(x>=2);
else if(r) modify_min(1,1,len,l,v[r]-v[l],0);
else modify_min(1,1,len,l,inf,0);
}
}
}
else{
int flag = 0;
int r = queryMin(1,1,len,t,len);
int l = queryMax(1,1,len,1,t);
int rc = query_min(1,1,len,t+1,len);
int lc = query_max(1,1,len,1,t-1);
// debug(t)
// debug(l)
// debug(r)
// debug(rc)
// debug(lc)
if(rc&&lc&&v[rc]-v[lc]<v[t]) flag = 1;
if(r<a[i]||l>a[i]) flag = 1;
if(flag) printf("Yes\n");
else printf("No\n");
}
}
}
/*
4
1 6
1 4
2 4
3 6
*/