题意:

  带修改的区间第K小.

SOL:

  看了很久很久很久很久的整体二分,网上的各种题解也不是很多,也一直很不了解所谓的"贡献","将询问一起递归"是什么意思...看了一晚上的代码终于有所领悟...

  什么是整体二分呢,"整体",整体整体什么是整体,整体就是将包括数,修改,询问一起二分,而如何实现呢?我看我能讲多少,那就算多少好了,还是代码更加直观.

  先贴一下XHR大神犇的论文-----整体二分满足的性质(虽然没有完全理解但好像也很有道理的样子):

    

    先讲一下判定答案是什么,我们对于一个询问时,我们可二分答案然后判断这个答案的rank,然后二分即可.在整体二分中,这个二分的值即为判定答案

    1.询问的答案具有可二分性(显然啊...不然怎么叫做二分...)

    2.修改对判定答案的贡献互相独立(比如说这个问题,添加一个比判定答案大,那么它就比判定答案大了,如果在添加一个比判定答案小的数,并不能对上一个修改构成什么影响...)

    3.修改如果对判定答案有贡献,则贡献为以确定的与判定标准无关的值

    4.贡献满足交换律,结合律,具有可加性.

    (3,4的解释还是贴XHR大神的吧...我根本不能怎么表达...

    因为贡献的值与判定标准无关,所以如果我们已经计算过某一些修改对询问的贡献,那么这个贡献永远不会改变------(若一个修改比判定答案大,那么它就比判定答案大了.你大爷永远是你大爷. ) 我们没有必要当判定标准改变时再次计算这部分修改的贡献,只要记录下当前的总贡献,在进一步二分时,直接加上新的贡献即可.

    这部分还是讲不清楚啊...还是看代码比较直观...

    5.题目允许离线算法(怎么感觉画风突变啊...一种忧桑的感觉)

    对于这个题目应该怎么考虑呢...我们将所有的操作添加进一个序列中,然后对所有的询问用同一个二分答案作为判定答案,然后将所有应该增大判定答案的放在一组,减小的放在一组...啊啊啊啊真心说不明白,看代码看代码...加几个注释.

CODE:

/*==========================================================================
# Last modified: 2016-02-25 21:09
# Filename: 1901.cpp
# Description:
==========================================================================*/
#define me AcrossTheSky
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector> #define lowbit(x) (x)&(-x)
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define FORP(i,a,b) for(int i=(a);i<=(b);i++)
#define FORM(i,a,b) for(int i=(a);i>=(b);i--)
#define ls(a,b) (((a)+(b)) << 1)
#define rs(a,b) (((a)+(b)) >> 1)
#define getlc(a) ch[(a)][0]
#define getrc(a) ch[(a)][1] #define maxn 100000
#define maxm 100000
#define pi 3.1415926535898
#define _e 2.718281828459
#define INF 1070000000
using namespace std;
typedef long long ll;
typedef unsigned long long ull; template<class T> inline
void read(T& num) {
bool start=false,neg=false;
char c;
num=0;
while((c=getchar())!=EOF) {
if(c=='-') start=neg=true;
else if(c>='0' && c<='9') {
start=true;
num=num*10+c-'0';
} else if(start) break;
}
if(neg) num=-num;
}
/*==================split line==================*/
struct Infor{
int pos,x,id,op,k,l,r,cur;
//k,l,r,cur,id专门针对询问,分别表示询问第k大,l,r表示询问的范围,cur表示贡献---->放到程序中更好解释,表示询问的序号
//pos表示修改或原序列数值在序列中的位置
//op表示操作类型:1表示在序列中的元素,2表示修改前的元素-----这里又有一个奇技淫巧,我们将所有的信息--->原序列,修改,询问放在一个区间中,那么对于一个修改,到目前为止应该在序列中的元素则为修改后的元素,就在区间中新建一个位置放原来那个数,标记为2,修改后的数标记为1.
//x表示修改或原序列中的数值
}q[maxn],temp[maxn];
int c[maxn],a[maxn],ans[maxn],tmp[maxn];
bool mark[maxn];
int n,m,cnt=0,num=0;
//树状数组相关==================================================
void add(int x,int t){
while (x<=n){
c[x]+=t;
x+=lowbit(x);
}
}
int query(int x){
int ret=0;
while(x>0){
ret+=c[x];x-=lowbit(x);
}
return ret;
}
//==============================================================
void solve(int l,int r,int L,int R){//l,r表示正在进行二分的区间,L,R表示答案的范围
if (l>r) return;
if (L==R) { //如果答案已经确定了,那么这个区间内每一个询问的答案都是L
FORP(i,l,r) if (q[i].op==3) ans[q[i].id]=L;
return;
}
int mid=rs(L,R);
FORP(i,l,r){ //对于区间内每个的每个操作
if (q[i].op==1 && q[i].x<=mid) add(q[i].pos,1);
//如果这个元素应该在序列中存在,并且它会对当前的答案产生影响,我们将该位置加上1.
if (q[i].op==2 && q[i].x<=mid) add(q[i].pos,-1);
//奇技淫巧
//如果这个元素的op为2,那么之前一定有一个相等元素其op为1并且其已经对答案造成影响,如今这个元素被修改那么我们相应的要将它对答案的影响减去.
if (q[i].op==3) tmp[i]=query(q[i].r)-query(q[i].l-1);
//如果当前操作是询问操作,注意到一个时间性质,在这个询问之后的修改对这个询问没有影响,我们统计这个点询问范围内的贡献.
}
FORP(i,l,r){ //重置树状数组
if (q[i].op==1 && q[i].x<=mid) add(q[i].pos,-1);
if (q[i].op==2 && q[i].x<=mid) add(q[i].pos,1);
}
int tot=0;//统计在将区间二分时靠右操作的个数
FORP(i,l,r){//划分操作
if (q[i].op==3){ //这里就能体现cur的作用,如果当前比判断答案小的个数加上已经比判断答案小的个数大于k,那么我们要将判断答案减小,对于所有要这么操作的我们将它划到左边----于是就可以统一将判定答案的范围减小
if (q[i].cur+tmp[i]>=q[i].k) mark[i]=true,tot++;
else mark[i]=false, q[i].cur+=tmp[i];
}
else{
if (q[i].x<=mid) tot++,mark[i]=true; //对答案造成影响的,判定答案减小后仍可能造成影响.所以我们将它划到右边
else mark[i]=false;
}
}
int la=l,lb=l+tot;
FORP(i,l,r)
if (mark[i]) temp[la++]=q[i];
else temp[lb++]=q[i];
FORP(i,l,r) q[i]=temp[i]; //复制粘贴的过程
solve(l,la-1,L,mid);
solve(la,lb-1,mid+1,R); //整体二分的过程. 非常6
}
int main(){
//freopen("a.in","r",stdin);
//freopen("tmp.out","w",stdout);
read(n); read(m);
FORP(i,1,n){
read(a[i]);
q[++num].x=a[i]; q[num].pos=i; q[num].op=1; q[num].id=0;
} //读入原序列
FORP(i,1,m){
char s[5]; scanf("%s",s);
if (s[0]=='Q'){
int x,y,z; read(x); read(y); read(z);
q[++num].l=x; q[num].r=y; q[num].k=z;
q[num].id=++cnt; q[num].op=3;
}//读入询问
else {
int x,t;
read(t); read(x);
q[++num].x=a[t]; q[num].pos=t; q[num].id=0; q[num].op=2;//奇技淫巧,增加一个操作
q[++num].x=x; q[num].pos=t; q[num].id=0; q[num].op=1;
a[t]=x;
}//读入修改操作
}
solve(1,num,0,INF); //整体二分
FORP(i,1,cnt) printf("%d\n",ans[i]);//输出
}

BZOJ 1901 & 整体二分的更多相关文章

  1. BZOJ 2527 & 整体二分

    Byteotian Interstellar Union有N个成员国.现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站. 这个星球经常会下陨石雨 ...

  2. BZOJ 1901 Zju2112 Dynamic Rankings ——整体二分

    [题目分析] 上次用树状数组套主席树做的,这次用整体二分去水. 把所有的查询的结果一起进行二分,思路很好. [代码] #include <cstdio> #include <cstr ...

  3. bzoj 1901: Zju2112 Dynamic Rankings【整体二分+树状数组||主席树+树状数组】

    整体二分: 对于每一个修改操作,标记为1,并且加一个标记为-1的这个位置原来值,并且对于a数列每个点都当成修改操作 然后整体二分,扫当前操作区间lr,把在值域区间标记为1和-1的操作都在树状数组对应位 ...

  4. BZOJ 1901 Dynamic Rankings (整体二分+树状数组)

    题目大意:略 洛谷传送门 这道题在洛谷上数据比较强 貌似这个题比较常见的写法是树状数组套主席树,动态修改 我写的是整体二分 一开始的序列全都视为插入 对于修改操作,把它拆分成插入和删除两个操作 像$C ...

  5. BZOJ.4009.[HNOI2015]接水果(整体二分 扫描线)

    LOJ BZOJ 洛谷 又是一个三OJ rank1!=w= \(Description\) (还是感觉,为啥非要出那种题目背景啊=-=直接说不好么) 给定一棵树和一个路径集合(每条路径有一个权值).\ ...

  6. bzoj 2527 Meteors - 整体二分 - 树状数组

    Description Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby gala ...

  7. BZOJ 2527 Meteors | 整体二分

    BZOJ 2527 Meteors 题意 一个圆环上有m个位置,编号为1~m,分别属于n个国家. 有k个时刻,每个时刻都会给圆环上的一个区间中每个位置的值加上一个数. 每个国家有一个目标,问对于每个国 ...

  8. BZOJ 3110 K大数查询 | 整体二分

    BZOJ 3110 K大数查询 题面 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个 ...

  9. BZOJ.2527.[POI2011]MET-Meteors(整体二分)

    题目链接 BZOJ 洛谷 每个国家的答案可以二分+求前缀和,于是可以想到整体二分. 在每次Solve()中要更新所有国家得到的值,不同位置的空间站对应不同国家比较麻烦. 注意到每次Solve()其国家 ...

随机推荐

  1. java 学习笔记——网络(Socket)

    阅读方法:将网页放大到200%. 如果你用过用过word应该知道按住ctrl键使用鼠标滚轮缩放.

  2. java07课堂作业

    一.动手动脑:多层的异常捕获-1 阅读以下代码(CatchWho.java),写出程序运行结果: public class CatchWho { public static void main(Str ...

  3. python 连接sql server

    linux 下pymssql模块的安装 所需压缩包:pymssql-2.1.0.tar.bz2freetds-patched.tar.gz 安装: tar -xvf pymssql-2.1.0.tar ...

  4. .netWeb方向:语言+技术

    常用语言+技术 C# T-Sql ADO.NEt JavaScript Asp.Net MVC HTML CSS DOM AJAX Entity Framework Regular expressio ...

  5. 【jquery】幻灯片效果

    闲着无聊,用Jquery写了一个幻灯片效果. 我这人喜欢造轮子,除了jquery这种有强大开发团队的框架级别JS,其实的一些小程序都是尽量自己写. 一是因为怕出问题了没人问,二是自己写的改起来也方便. ...

  6. oracle的oci和thin区别(数据源)

    我是今天看到tomcat数据源的配置时,想起来这个问题,刚开始还不晓得thin是什么东西! database.url=jdbc:oracle:thin:angel/oracle@192.168.55. ...

  7. AJax中post与get请求注意事项

    在使用ajax提交表单时,一定要区分提交按钮的形式和数据表头的设置,实例如下: GET请求: HTML代码: <!doctype html> <html lang="en& ...

  8. JqueryEasyUI 解决IE下datagrid无法刷新的问题 分类: JavaScript JqueryEasyUI 2014-09-20 10:05 510人阅读 评论(1) 收藏

    问题描述: 在使用JqueryEasyUI 时,发现在IE下$('#table').datagrid('reload');无效,数据并没有被刷新,究其原因,是因为刷新时,datagrid请求的url没 ...

  9. hdu 4035 2011成都赛区网络赛E 概率dp ****

    太吊了,反正我不会 /* HDU 4035 dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点 ...

  10. 解释一下SQLSERVER事务日志记录

    解释一下SQLSERVER事务日志记录 大家知道在完整恢复模式下,SQLSERVER会记录每个事务所做的操作,这些记录会存储在事务日志里,有些软件会利用事务日志来读取 操作记录恢复数据,例如:log ...