ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

知识补充:整体二分

2019-03-11 21:55:09  阅读:169  来源: 互联网

标签:二分 qr 补充 知识 ++ tot int ql op


例题:动态区间第k小

 

先上代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mid ((l+r)>>1)
#define lowbit(x) (x&-x)
#define N 50005
#define M 20005
using namespace std;
const int inf=1000000007;
struct zero{
    int x,y,k,op,id;
}q[N+M],q1[N+M],q2[N+M];
int tree[N],tot=0,n,m,ans[M];
int T,x,y,k,cnt=0;
int input[N];
char c;
void add(int a,int k){for(;a<=max(n,m);a+=lowbit(a))tree[a]+=k;}
int ask(int a){int ans=0;for(;a>0;a-=lowbit(a))ans+=tree[a];return ans;}
void solve(int ql,int qr,int l,int r){
  if(ql>qr)return;
  if(l==r){
      for(int i=ql;i<=qr;i++)
      if(q[i].op==0)ans[q[i].id]=l;
      return;
  }
  int t1=0,t2=0;
  for(int i=ql;i<=qr;i++){
    if(q[i].op){
        if(q[i].x<=mid)add(q[i].id,q[i].op),q1[++t1]=q[i];
        else q2[++t2]=q[i];
    }
    else{
        int sum=ask(q[i].y)-ask(q[i].x-1);
        if(sum>=q[i].k)q1[++t1]=q[i];
        else q[i].k-=sum,q2[++t2]=q[i];
    }
  }
for(int i=1;i<=t1;i++)if(q1[i].op)add(q1[i].id,-q1[i].op);
  for(int i=1;i<=t1;i++)q[i+ql-1]=q1[i];
  for(int i=1;i<=t2;i++)q[i+ql+t1-1]=q2[i];
  solve(ql,t1+ql-1,l,mid);
  solve(t1+ql,qr,mid+1,r);
}
int main(){
    scanf("%d",&T);
    while(T--){
        cnt=tot=0;
        memset(q,0,sizeof q);
        memset(tree,0,sizeof tree);
        memset(q1,0,sizeof q1);
        memset(q2,0,sizeof q2);
        memset(ans,0,sizeof ans);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",input+i);
            q[++tot].x=input[i],q[tot].op=1,q[tot].id=i;
        }
        for(int i=1;i<=m;i++){
            cin>>c;
            if(c=='C'){
                scanf("%d%d",&k,&x);
                q[++tot].x=input[k],q[tot].op=-1,q[tot].id=k;
                input[k]=x;
                q[++tot].x=input[k],q[tot].op=1,q[tot].id=k;
            }
            else {
                scanf("%d%d%d",&x,&y,&k);
                q[++tot].x=x,q[tot].y=y,q[tot].k=k,q[tot].op=0,q[tot].id=++cnt;
            }
        }
        solve(1,tot,-inf,inf);
        for(int i=1;i<=cnt;i++)printf("%d\n",ans[i]);
   }

}

解释一下struct zero:

对于修改函数:x表示修改的值,op表示该操作是修改还是查寻,id为该操作作用点在数组中的位置

对于查寻函数:x,y表示查寻区间,k表示在这区间中查找第k小,op和id意义同上

 

整体二分的主要思路就是把一段操作(修改和查寻)序列分成两段,分治操作

solve(ql,t1+ql-1,l,mid);
solve(t1+ql,qr,mid+1,r);

就是这样

 

那么怎么分段呢

 

我们来看solve(ql,qr,l,r)函数,

这里ql,qr,l,r的意义就是序列中ql到qr的所有询问,它的答案在l到r之间


算了我在代码里讲吧,那么请继续看代码

void solve(int ql,int qr,int l,int r){
  if(ql>qr)return;//特判防RE
  if(l==r){//l==r代表答案已经确定了,那么把ql到qr中所有询问答案赋成l
      for(int i=ql;i<=qr;i++)
      if(q[i].op==0)ans[q[i].id]=l;
      return;
  }
  int t1=0,t2=0;
  for(int i=ql;i<=qr;i++){
    if(q[i].op){
        if(q[i].x<=mid)add(q[i].id,q[i].op),q1[++t1]=q[i];//q[i]/x<=mid代表这个修改对ql到qr区间内的查寻有影响,我们把它加到树状数组里,又因为答案在l~mid里的询问又会受它影响
//所以要把它丢进q1继续发挥作用.至于答案在mid+1~r里的询问,虽然受它影响,但影响为定值,所以我们用树状数组计算出这个值即可消去影响 else q2[++t2]=q[i];//对答案在l~mid里的询问没影响,加入q2影响后半段 } else{ int sum=ask(q[i].y)-ask(q[i].x-1); if(sum>=q[i].k)q1[++t1]=q[i];//同理,sum>=q[i].k表示q[i]的答案在l~mid内,查寻l~mid else q[i].k-=sum,q2[++t2]=q[i];//否则,减去先前的影响(定值)消去影响 } } for(int i=1;i<=t1;i++)if(q1[i].op)add(q1[i].id,-q1[i].op);//重置树状数组 for(int i=1;i<=t1;i++)q[i+ql-1]=q1[i]; for(int i=1;i<=t2;i++)q[i+ql+t1-1]=q2[i]; solve(ql,t1+ql-1,l,mid); solve(t1+ql,qr,mid+1,r);//分治 }

然后注意main里把一个点变成x的操作要拆成两个操作实现

            if(c=='C'){
                scanf("%d%d",&k,&x);
                q[++tot].x=input[k],q[tot].op=-1,q[tot].id=k;
                input[k]=x;
                q[++tot].x=input[k],q[tot].op=1,q[tot].id=k;
            }

 

标签:二分,qr,补充,知识,++,tot,int,ql,op
来源: https://www.cnblogs.com/stepsys/p/10513379.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有