51nod 1981 如何愉快地与STL玩耍

Description

驴蛋蛋在愉快地与STL玩耍
突然间小A跳了出来对驴蛋蛋说,看你与STL玩的很开心啊,那我给你一个大小为N的vector,这个vector上每个位置上是一个set,
每次我会在闭区间 [L,R] 中的每个set里插入一个数c,或者询问 [L,R] 区间所有set里所有数拿下来排序之后的严格第 K 小,现在你还开心吗,红红火火恍恍惚惚韩寒会画红槐花!!!!
小A走了,留下驴蛋蛋一个人外加一个长度为 N 的vector<set >在风中凌乱,你能帮驴蛋蛋解除凌乱吗?

根据小A的 ℂ++𝟚.𝟛𝟛 标准vector可以被视作一个数组,下标从 1 开始,大小不得超过 65536
set是一个集合,其中的数不得超过 10000 并且会被自动去重
小A最多会进行 Q 次(不超过 65536 )完全符合 ℂ++𝟚.𝟛𝟛 标准的操作,但如果出现询问时 [L,R] 区间里不足 K 个数的情况,你只需要对小A回答 −1 就好了

Solution

听说可以线段树+bitset直接水过,也可以整体二分做
和普通的整体二分唯一的不同就是就是需要去重
有一个套路:两个区间有交,可以写成 \(R>=l\) && \(r>=L\) 的形式
也就是说我们把修改映射成平面上的点 \((r,l)\),那么查询就是问 \((L,R)\) 右下角的点数之和

考虑去重:
假设两个点 \((x,y)\) 的权值相同
1.如果 \(x\)\(y\) 的右下方,\(x\) 包含了 \(y\),那么 \(y\) 就没有用了,可以直接去掉
2.如果不是包含关系,只是普通的相交关系,那么就容斥一下即可,像下面这个图一样,给每一个一个权值,改为查询权值和

这个东西可以对每一个权值开一个 \(set\) 来维护

#include<bits/stdc++.h>
using namespace std;
const int N=80005;
int n,Q,cnt=0,rt[N],ans[N],DEP=0,c[N],ct[N];
struct sub{
	int op,l,r,k,id;
	bool operator <(const sub &p)const{return r<p.r;}
}q[N],A[N],B[N];
set<sub>S[N];
struct node{int ls,rs,w;}tr[N*100];
inline void ins(int &x,int l,int r,int sa,int t){
	if(!x)x=++cnt;tr[x].w+=t;
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(sa<=mid)ins(tr[x].ls,l,mid,sa,t);
	else ins(tr[x].rs,mid+1,r,sa,t);
}
inline void add(int sta,int p,int t){
	for(int i=sta;i;i-=(i&(-i))){
		if(ct[i]!=DEP)ct[i]=DEP,rt[i]=0;
		ins(rt[i],1,n,p,t);
	}
}
inline int qry(int x,int l,int r,int sa,int se){
	if(!x)return 0;
	if(sa<=l && r<=se)return tr[x].w;
	int mid=(l+r)>>1;
	if(se<=mid)return qry(tr[x].ls,l,mid,sa,se);
	else if(sa>mid)return qry(tr[x].rs,mid+1,r,sa,se);
	else return qry(tr[x].ls,l,mid,sa,mid)+qry(tr[x].rs,mid+1,r,mid+1,se);
}
inline int query(int sta,int p){
	int ret=0;
	for(int i=sta;i<=n;i+=(i&(-i)))if(ct[i]==DEP)ret+=qry(rt[i],1,n,1,p);
	return ret;
}
inline void insert(sub t){
	int k=t.k;
	if(c[k]!=DEP)c[k]=DEP,S[k].clear();
	if(S[k].empty()){add(t.r,t.l,1),S[k].insert(t);return ;}
	set<sub>::iterator i,j,x;

	i=S[k].upper_bound(t);
	if(i!=S[k].end() && i->l<=t.l)return ;
	if(i==S[k].begin()){
		S[k].insert(t);
		add(t.r,t.l,1);add(t.r,i->l,-1);
		return ;
	}
	j=i;j--;
	if(j->r==t.r && j->l<=t.l)return ;
   if(i!=S[k].end())add(j->r,i->l,1),add(t.r,i->l,-1);
	add(t.r,t.l,1);
	while(j->l>=t.l){
		add(j->r,j->l,-1);
		if(j!=S[k].begin()){
			x=j;--x;
			add(x->r,j->l,1);
			S[k].erase(j);j=x;
		}
		else{S[k].erase(j);j=S[k].end();break;}
	}
	if(j!=S[k].end())add(j->r,t.l,-1);S[k].insert(t);
}
inline void solve(int l,int r,int L,int R){
	if(l==r){
		for(int i=L,t=l>10000?-1:l;i<=R;i++)
			if(q[i].op==1)ans[q[i].id]=-2;
			else ans[q[i].id]=q[i].k?t:-1;
		return ;
	}
	for(int i=1;i<=cnt;i++)tr[i].ls=tr[i].rs=tr[i].w=0;cnt=0;
	int mid=(l+r)>>1;DEP++;
	int xl=0,xr=0,p=L-1,t;
	for(int i=L;i<=R;i++){
		if(q[i].op==1){
			if(q[i].k<=mid)A[++xl]=q[i],insert(q[i]);
			else B[++xr]=q[i];
		}
		else if((t=query(q[i].l,q[i].r))>=q[i].k)A[++xl]=q[i];
		else q[i].k-=t,B[++xr]=q[i];
	}
	for(int i=1;i<=xl;i++)q[++p]=A[i];
	for(int i=1;i<=xr;i++)q[++p]=B[i];
	if(xl)solve(l,mid,L,L+xl-1);if(xr)solve(mid+1,r,R-xr+1,R);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d%d",&n,&Q);
  for(int i=1;i<=Q;i++){
	  scanf("%d%d%d%d",&q[i].op,&q[i].l,&q[i].r,&q[i].k);
	  q[i].id=i;ans[i]=-1;
  }
  solve(0,10001,1,Q);
  for(int i=1;i<=Q;i++)if(ans[i]!=-2)printf("%d\n",ans[i]);
  return 0;
}

posted @ 2018-04-13 20:07  PIPIBoss  阅读(128)  评论(0)    收藏  举报