ZOJ2112

动态求区间第k小,整体二分蛤不清be(菜哭.jpg ,给Qt的板子注释了一蛤

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e4 + 7;
const int M = 1e5 + 7;
const int INF = 1 << 30;

struct Quiry
{
  int x,y,z,id,tp;
}Q[ N + M ],q1[ N + M ],q2[ N + M ];

int n,m,cnt,a[N],ans[N],x,y,z,idx;

struct Bit
{
  int T[N];
  int n;
  inline void init(int c){n=c;memset(T, 0, sizeof(T));}
  inline void add(int x,int y){for(;x<=n;x+=x&-x)T[x] += y;}
  inline int sum(int u)
  {
  	int ans = 0;
  	for(;u;u-=u&-u)ans += T[u];
  	return ans;
  }
}BIT;

inline void solve(int l,int r,int AL,int AR)
{	//l,r这段操作和询问的区间,二分答案AL,AR 
  if(l>r)return;
  if(AL==AR)		//这段区间的询问的答案就是AL 
  {
    for(int i=l;i<=r;++i)
    if(Q[i].tp==2) ans[Q[i].id] = AL;
    return;
  }
  
  int AM = (AL + AR) >> 1;
  int p1=0,p2=0;
  
  for(int i=l;i<=r;++i)
  {
  	if(Q[i].tp==1)	//种类1是添加值 
  	{
  	  if(Q[i].x<=AM)	//要加的值小于二分值 
  	  {
  	  	BIT.add(Q[i].id,Q[i].y);//y就是+1还是-1 
  	  	q1[++p1] = Q[i];	//有贡献的记录下来 
  	  }
  	  else q2[++p2] = Q[i];	//没贡献的记录下来 
  	}
  	else
  	{	//对于当前这个询问,在x到y的区间有多少比二分的答案小的 
  	  int del = BIT.sum(Q[i].y) - BIT.sum(Q[i].x-1);
  	  if(del >= Q[i].z)q1[++p1] = Q[i];	//如果超出了询问的k 
  	  else								//用q1记录下来 
  	  {
  	  	Q[i].z -= del;//否则就把那个k减掉当前贡献del 
  	  	q2[++p2] = Q[i];//丢进q2 
  	  }
  	}
  }
  	for(int i=1;i<=p1;++i)//q1中那些添加值有贡献的全部减掉 
	  if(q1[i].tp==1)BIT.add(q1[i].id,-q1[i].y);
  	//q1数组放到前面,q2数组放到后面 
  	for(int i=1;i<=p1;++i)Q[i+l-1] = q1[i];
  	for(int i=1;i<=p2;++i)Q[i+p1+l-1] = q2[i];
  	//先处理前半部分,再处理后半部分 
  	solve(l,l+p1-1,AL,AM);//前半部分是对后面可能有贡献修改和已经超过k的询问 
  	solve(l+p1,r,AM+1,AR);//后半部分是对l,r区间都没修改而且 
//这两个区间互不影响,但每个区间中的是按照时间顺序来的  	
}

int main()
{
  int T;
  scanf("%d\n",&T);
  while(T--)
 {
  scanf("%d%d\n",&n,&m);
  cnt = idx = 0;
  for(int i=1;i<=n;++i)
  {
  	scanf("%d",a+i);					// tp 种类1  
  	Q[++cnt] = (Quiry){a[i],1,0,i,1};//x要加的值,y1添加,z0
  }									//id i位置,
  for(int i=1;i<=m;++i)
  {
  	char opt[2];
    scanf("%s%d%d",opt,&x,&y);
    if(*opt=='Q')
    {
      scanf("%d\n",&z);					//x到y区间第z小 
      ++idx;							//idx询问,种类2 
	  Q[++cnt] = (Quiry){x,y,z,idx,2};
    }
    else
    {
      Q[++cnt] = (Quiry){a[x],-1,0,x,1};//id x位置 tp种类1  
      a[x]=y;							//x a[x],y-1删除,z 0 
      Q[++cnt] = (Quiry){a[x],1,0,x,1};
    }
  }
  BIT.init(n);
  solve(1,cnt,-INF,INF);
  for(int i=1;i<=idx;++i)printf("%d\n",ans[i]);
 }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值