H.Happy Triangle
维护一个集合。集合支持三种操作。1、往集合里加入一个元素x。2、往集合里删除一个容器x。3、给定一个x,询问是否能从容器找找到y,z,使得x,y,z能组成三角形。操作数<=10^5,x<=10^9。
先将所有的x离散化。然后可用权值线段树。维护权值线段树的最大值最小值,数量和区间最小差值。
总共有三种可能。
1、x<=y<=z 此时,我们需要找到y-z的最小差值。这就是要维护区间最小差的原因。
2、y<=x<=z 此时,需要找到小于x且最大的y,大于x且最小的z,然后判断能否组成三角形。线段树上直接搜即可。
3、y<=z<=x 此时,找到小于x且前2大的数,然后判断能否组成三角形。
#include#define N 205000 #define inf 0x3f3f3f3f using namespace std; map mp; int a[N]; int b[N]; int op[N]; int n; void lisan() { int i,x; for (i=1;i<=n;i++) b[i]=a[i]; sort(b+1,b+1+n); for (i=1;i<=n;i++) { x=lower_bound(b+1,b+1+n,a[i])-b; mp[x]=a[i]; a[i]=x; } } struct node{ int left,right,interval,sum; }tree[N<<2]; void pushup(int rt) { tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum; tree[rt].interval=min(tree[rt<<1].interval,tree[rt<<1|1].interval); tree[rt].left=min(tree[rt<<1].left,tree[rt<<1|1].left); tree[rt].right=max(tree[rt<<1].right,tree[rt<<1|1].right); if (tree[rt<<1].sum>0&&tree[rt<<1|1].sum>0) tree[rt].interval=min(tree[rt].interval,mp[tree[rt<<1|1].left]-mp[tree[rt<<1].right]); } void build(int l,int r,int rt){ if (l==r) { tree[rt].left=inf; tree[rt].right=0; tree[rt].sum=0; tree[rt].interval=inf; return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(rt); } void add(int l,int r,int x,int s,int rt) { if (l==r) { tree[rt].sum+=s; if (tree[rt].sum>0) { tree[rt].left=x; tree[rt].right=x; } else { tree[rt].left=inf; tree[rt].right=0; } if (tree[rt].sum>1) tree[rt].interval=0; else tree[rt].interval=inf; return; } int m=(l+r)>>1; if (x<=m) add(l,m,x,s,rt<<1); else add(m+1,r,x,s,rt<<1|1); pushup(rt); } int query_max(int l,int r,int x,int rt) { if (tree[rt].sum==0) { return -1; } if (l==r) { return tree[rt].left; } int m=(l+r)>>1; if (x<=m) return query_max(l,m,x,rt<<1); else return max(tree[rt<<1].right,query_max(m+1,r,x,rt<<1|1)); } int query_min(int l,int r,int x,int rt) { if (tree[rt].sum==0) { return inf; } if (l==r) { return tree[rt].left; } int m=(l+r)>>1; if (x>m) return query_min(m+1,r,x,rt<<1|1); else return min(tree[rt<<1|1].left,query_min(l,m,x,rt<<1)); } node query_int(int l,int r,int x,int rt) { node tmp,re; if (tree[rt].sum==0) { return tree[rt]; } if (l==r) { return tree[rt]; } int m=(l+r)>>1; if (x>m) return query_int(m+1,r,x,rt<<1|1); else { tmp=query_int(l,m,x,rt<<1); re.sum=tmp.sum+tree[rt<<1|1].sum; re.interval=min(tmp.interval,tree[rt<<1|1].interval); re.left=min(tmp.left,tree[rt<<1|1].left); re.right=max(tmp.right,tree[rt<<1|1].right); if (tmp.sum>0&&tree[rt<<1|1].sum>0) re.interval=min(re.interval,mp[tree[rt<<1|1].left]-mp[tmp.right]); return re; } } int main(){ int e,t,x,y; node p; int i; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d %d",&op[i],&a[i]); lisan(); build(1,n,1); for (i=1;i<=n;i++) { if (op[i]==1) { add(1,n,a[i],1,1); } if (op[i]==2) { add(1,n,a[i],-1,1); } if (op[i]==3) { //x<=a[i]<=y x=query_max(1,n,a[i],1); // max<=a[i] add(1,n,x,-1,1); y=query_min(1,n,a[i],1); add(1,n,x,1,1); if (x!=-1&&y!=inf) if (mp[x]+mp[a[i]]>mp[y]) {printf("Yes ");continue;} y=query_min(1,n,a[i],1);// max<=a[i] add(1,n,y,-1,1); x=query_max(1,n,a[i],1); add(1,n,y,1,1); if (x!=-1&&y!=inf) if (mp[x]+mp[a[i]]>mp[y]) {printf("Yes ");continue;} //a[i]<=x<=y p=query_int(1,n,a[i],1); x=p.interval; if (x!=inf) if (mp[a[i]]>x) {printf("Yes ");continue;} //x<=y<=a[i] x=query_max(1,n,a[i],1); add(1,n,x,-1,1); y=query_max(1,n,a[i],1); add(1,n,x,1,1); if (x!=-1&&y!=-1) if (mp[x]+mp[y]>mp[a[i]]) {printf("Yes ");continue;} printf("No "); } } }