列表

详情


NC21847. Problem E. Jhadgre的合唱队形

描述

为了即将到来的合唱比赛,Jhadgre作为班长,决定给同学们重新编一次队。

他先用一个整数 hi 表示每个人的身高等级(hi∈[1,N]),然后进行编队。

但是显然单排的队伍已经out了,所以Jhadgre发明了一种新的排队方式。

他希望每次可以在几个连续的队列最后各加入一个身高等级相同的人,当然为了掌控全局的身高,他也希望可以随时知道几个连续的队列中身高排序的情况。

所以整个编队方式过程可以简化成两种操作:

每次操作由四个数组成:op x y z  (x<=y<=N)
  1. 对于第1种操作 :每次选择在第x列到第y列每一列最后加入一个身高等级为z的人。
  2. 对于第2种操作 :每次询问在第 x 列到第 y 列的所有人中,第 z 高的人的身高等级是多少。
例如:op = 1 , x = 1 , y = 2 , z = 1 表示在第1列和第2列最后分别加入一个身高等级为1的人。

           op = 2 , x = 1 , y = 3 , z = 1表示询问在第1列到第3列中,第1高的人的身高等级是多少。

Jhadgre马上就要去给同学们排队了,他准备进行 M次操作来排这个队,他希望可以先模拟一下这些操作,但是他的想象力又不支持他凭想象做这个模拟,所以只能场外求助了...



输入描述

只有一组数据,第一行包含两个整数N,M,意义如题。
接下去M行,每行包含4个整数,如题目描述。

输出描述

对于每个询问的回答。

示例1

输入:

2 6
1 1 2 1
1 1 2 2
2 1 1 1
2 1 1 2
2 1 2 2
2 1 2 3

输出:

2
1
2
1

说明:

第一个操作后,第1列和第2列中分别有一个身高等级为1的人。
第二个操作后,第1列和第2列中分别有两个人,身高等级分别为1,2。
第三个操作询问第1列中身高等级最大的人的身高等级,此时第1列中有两个人,身高等级分别为1,2,所以身高等级最大的是2
第四个操作询问第1列中身高等级第2大的人的身高等级,此时第1列中有两个人,身高等级分别为1,2,所以身高等级第2大的是1
第五个操作询问第1列到第2列中身高等级第2大的人的身高等级,此时第1列和第2列中共有四个人,身高等级为1,1,2,2,所以身高等级第2大的是2
第六个操作询问第1列到第2列中身高等级第3大的人的身高等级,此时第1列和第2列中共有四个人,身高等级为1,1,2,2,所以身高等级第3大的是1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 111ms, 内存消耗: 4300K, 提交时间: 2018-12-22 14:00:00

#include<bits/stdc++.h>
using namespace std;
const int N=50005;
typedef long long ll;
int n,m,i;
int op[N],x[N],y[N],z[N];
int qid[N];
int ans[N];
ll bi1[N],bi2[N];
inline void add(ll*a,int x,int v){for(;x<=n;x+=x&-x)a[x]+=v;}
inline ll query(ll*a,int x){ll ans=0;for(;x;x-=x&-x)ans+=a[x];return ans;}
inline void add(int l,int r,int v){
	add(bi1,l,v);add(bi1,r+1,-v);
	add(bi2,l,v*(l-1));add(bi2,r+1,-r*v);
}
inline ll sum(int x){return 1ll*query(bi1,x)*x-query(bi2,x);}
inline ll sum(int l,int r){return sum(r)-sum(l-1);}
void solve(int a,int b,int c,int d){
	if(a>b)return;
	if(c==d){
		for(int i=a;i<=b;++i)if(op[qid[i]]==2)ans[qid[i]]=c;
		return;
	}
	int mid=(c+d)>>1,i;
	static ll ff[N];
	memset(ff+a,0,(b-a+1)<<3);
	//{std::cerr<<sum(26890,30000)<<'\n';exit(0);}
	for(i=a;i<=b;++i){
		if(op[qid[i]]==1 && z[qid[i]]<=mid){
			add(x[qid[i]],y[qid[i]],1);
		}
	//if(i==2){std::cerr<<sum(30000)<<'\n';exit(0);}
		if(op[qid[i]]==2)ff[i]+=sum(x[qid[i]],y[qid[i]]);
	}
	//std::cerr<<sum( 26890,30428)<<'\n';exit(0);
	static int ql[N],qr[N];int lxb=0,rxb=0;
	for(i=a;i<=b;++i){
		if(op[qid[i]]==1 && z[qid[i]]<=mid){
			add(x[qid[i]],y[qid[i]],-1);
		}
	}
	for(i=a;i<=b;++i){
		if(op[qid[i]]==1){
			if(z[qid[i]]<=mid)ql[++lxb]=qid[i];else qr[++rxb]=qid[i];
		}else{
			if(ff[i]>=z[qid[i]])ql[++lxb]=qid[i];else qr[++rxb]=qid[i],z[qid[i]]-=ff[i];
		}
	}
	for(i=1;i<=lxb;++i)qid[a-1+i]=ql[i];
	for(i=1;i<=rxb;++i)qid[a+lxb-1+i]=qr[i];
	solve(a,a+lxb-1,c,mid);solve(a+lxb,b,mid+1,d);
}
int main(){
	//freopen("1.txt","r",stdin);
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>m;
	for(i=1;i<=m;++i){
		cin>>op[i]>>x[i]>>y[i]>>z[i],qid[i]=i;
		if(op[i]==1)z[i]=-z[i];
	}
	solve(1,m,-n-1,n+1);
	for(i=1;i<=m;++i)if(op[i]==2)cout<<-ans[i]<<'\n';
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 688ms, 内存消耗: 64864K, 提交时间: 2019-01-07 18:24:48

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,now,rt,cnt=0,root[200005],tag[15000005],lc[15000005],rc[15000005];
unsigned int sumv[15000005];
int Hash[50005];
struct operation{
 int op,a,b,c;
}a[50005];
int getid(int a){
 return lower_bound(Hash+1,Hash+Hash[0]+1,a)-Hash;
}
void upd(int &o,int l,int r,int L,int R){
 if(!o) o=++cnt;
 sumv[o]+=R-L+1;
 if(L==l&&R==r)
 {
  tag[o]++;
  return;
 }
 int mid=(l+r)/2;
 if(R<=mid) upd(lc[o],l,mid,L,R);
 else if(L>mid) upd(rc[o],mid+1,r,L,R);
 else
 {
  upd(lc[o],l,mid,L,mid);
  upd(rc[o],mid+1,r,mid+1,R);
 }
}
void update(int o,int l,int r,int k){
 upd(root[o],1,n,a[now].a,a[now].b);
 if(l==r) return;
 int mid=(l+r)/2;
 if(k<=mid) update(o*2,l,mid,k);
 else update(o*2+1,mid+1,r,k);
}
unsigned int qry(int o,int l,int r,int L,int R){
 if(!o) return 0;
 if(L==l&&R==r) return sumv[o];
 int mid=(l+r)/2;
 unsigned int ans=tag[o]*(R-L+1);
 if(R<=mid) ans+=qry(lc[o],l,mid,L,R);
 else if(L>mid) ans+=qry(rc[o],mid+1,r,L,R);
 else ans+=qry(lc[o],l,mid,L,mid)+qry(rc[o],mid+1,r,mid+1,R);
 return ans;
}
int query(int o,int l,int r,int k){
 if(l==r) return l;
 int mid=(l+r)/2;
 unsigned int siz=qry(root[o*2+1],1,n,a[now].a,a[now].b);
 if(k>siz) return query(o*2,l,mid,k-siz);
 else return query(o*2+1,mid+1,r,k);
}
int main(){
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++){
  scanf("%d%d%d%d",&a[i].op,&a[i].a,&a[i].b,&a[i].c);
  if(a[i].op==1) Hash[++Hash[0]]=a[i].c;
 }
 sort(Hash+1,Hash+Hash[0]+1);
 Hash[0]=unique(Hash+1,Hash+Hash[0]+1)-Hash-1;
 for(int i=1;i<=m;i++){
  now=i;
  if(a[i].op==1) update(1,1,50000,getid(a[i].c));
  else printf("%d\n",Hash[query(1,1,50000,a[i].c)]);
 }
 return 0;
}

上一题