记录编号 129601 评测结果 AAAAAAAAAA
题目名称 [ZJOI 2013] K大数查询 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.494 s
提交时间 2014-10-20 10:41:07 内存使用 3.94 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int SIZEN=50010,SIZEM=50010,INF=0x7fffffff;
class TARRAY{//改段求段的树状数组
public:
	int n;
	//我们设在数组A上进行操作,数组B:A[1~i]被整体加了多少,数组C=B[i]*i
	//则A[1~i]的前缀和为:i*(B[i]+...+B[N])+(C[1]+...+C[i-1])
	//我们需要维护B的前缀和(s)及C的后缀和(rs)
	int s[SIZEN];
	int rs[SIZEN];
	void clear(int x){n=x;memset(s,0,sizeof(s));memset(rs,0,sizeof(rs));}
	int lowbit(int x){return x&(-x);}
	void prefchange(int x,int t){
		if(x<1) return;
		for(int i=x;i>0;i-=lowbit(i)) s[i]+=t;
		for(int i=x;i<=n;i+=lowbit(i)) rs[i]+=x*t;
	}
	int prefsum(int x){
		if(x<1) return 0;
		int b=0,c=0;
		for(int i=x;i<=n;i+=lowbit(i)) b+=s[i];
		for(int i=x-1;i>0;i-=lowbit(i)) c+=rs[i];
		return b*x+c;
	}
	void change(int l,int r,int t){
		prefchange(r,t);
		prefchange(l-1,-t);
	}
	int segsum(int l,int r){
		return prefsum(r)-prefsum(l-1);
	}
};
class OPT{
public:
	int id,cmd;
	int a,b,c;
	void print(void){cout<<id<<" "<<cmd<<" "<<a<<" "<<b<<" "<<c<<endl;}
};
OPT s[SIZEM];
int ans[SIZEM]={0};
int cnt[SIZEM]={0};
TARRAY T;
OPT s1[SIZEM],s2[SIZEM];
void solve(int a,int b,int l,int r){//已确定s[a]~s[b]的操作与答案均在[l,r]区间内
	if(l==r){
		for(int i=a;i<=b;i++) if(s[i].cmd==2) ans[s[i].id]=l;
		return;
	}
	int mid=(LL)(l+r)/2;
	//下面2我们只统计那些>=mid+1的修改
	for(int i=a;i<=b;i++){
		if(s[i].cmd==1){//这是一个修改
			if(s[i].c>=mid+1) T.change(s[i].a,s[i].b,1);
		}
		else if(s[i].cmd==2){
			cnt[i]=T.segsum(s[i].a,s[i].b);
		}
	}
	for(int i=a;i<=b;i++)//再改回去......
		if(s[i].cmd==1&&s[i].c>=mid+1) T.change(s[i].a,s[i].b,-1);
	int p1=0,p2=0;
	for(int i=a;i<=b;i++){//第一部分是<=mid的
		if(s[i].cmd==1){
			if(s[i].c<=mid) s1[p1++]=s[i];
			else s2[p2++]=s[i];
		}
		else if(s[i].cmd==2){
			if(cnt[i]>=s[i].c) s2[p2++]=s[i];
			else s[i].c-=cnt[i],s1[p1++]=s[i];
		}
	}
	for(int i=0;i<p1;i++) s[a+i]=s1[i];
	for(int i=0;i<p2;i++) s[a+p1+i]=s2[i];
	solve(a,a+p1-1,l,mid);
	solve(a+p1,b,mid+1,r);
}
int N,M,qn=0;
int mn=INF,mx=0;
void answer(void){
	for(int i=1;i<=qn;i++) printf("%d\n",ans[i]);
}
void read(void){
	scanf("%d%d",&N,&M);
	T.clear(N);
	for(int i=1;i<=M;i++){
		scanf("%d%d%d%d",&s[i].cmd,&s[i].a,&s[i].b,&s[i].c);
		if(s[i].cmd==2) s[i].id=++qn;
		else mn=min(mn,s[i].c),mx=max(mx,s[i].c);
	}
}
int main(){
	freopen("zjoi13_sequence.in","r",stdin);
	freopen("zjoi13_sequence.out","w",stdout);
	read();
	solve(1,M,mn,mx);
	answer();
	return 0;
}