题目链接 BZOJ

洛谷


整体二分求的是第K小(利用树状数组)。求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\)。

注意到所有数的绝对值\(\leq N\),将所有数的大小关系反过来 第\(K\)大就是第\(K\)小了。所有数\(A[i]\)改为\(n-A[i]\),输出的时候也改为\(n-Ans[i]\)。

区间加入一个数\(C\)可以直接用线段树区间加,也可以树状数组维护常数会小很多。

\(n*m=2.5*1e9 > MAX\_INT\) 也是没谁了。。

现学了一波树状数组区间修改区间查询...->见这里

洛谷Rank1在BZOJ上60多。。


树状数组:

//4976KB	1220MS
#include <cstdio>
#include <cctype>
#include <algorithm>
#define lb(x) (x&-x)
//#define gc() getchar()
#define MAXIN 50000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=50005; int n,m,A[N],Ans[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Operation
{
LL K; int l,r,pos;//K!=0:Query [l,r] K; K=0:Add [l,r] pos.
Operation() {}
Operation(LL K,int l,int r,int p):K(K),l(l),r(r),pos(p) {}
}q[N],q1[N],q2[N]; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline LL readll()
{
LL now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
namespace T
{
int n;
LL sum1[N],sum2[N]; inline void Modify(int p,int v)
{
for(int i=p; i<=n; i+=lb(i))
sum1[i]+=v, sum2[i]+=p*v;
}
inline void Modify_Range(int l,int r,int v){
Modify(l,v), Modify(r+1,-v);
}
inline LL Query(int p)
{
LL res1=0,res2=0;
for(int i=p; i; i^=lb(i))
res1+=sum1[i], res2+=sum2[i];
return res1*(p+1)-res2;
}
inline LL Query_Range(int l,int r){
return Query(r)-Query(l-1);
}
}
void Solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r){
for(int i=h; i<=t; ++i) if(q[i].K) Ans[q[i].pos]=l;
return;
}
bool goon=0;//无询问时直接return。
for(int i=h; i<=t; ++i) if(q[i].K) {goon=1; break;}
if(!goon) return; int mid=l+r>>1, t1=0, t2=0;
for(int i=h; i<=t; ++i)
if(q[i].K)
{
LL tmp=T::Query_Range(q[i].l,q[i].r);
if(tmp>=q[i].K) q1[t1++]=q[i];
else q[i].K-=tmp, q2[t2++]=q[i];
}
else
{
if(q[i].pos<=mid) T::Modify_Range(q[i].l,q[i].r,1), q1[t1++]=q[i];
else q2[t2++]=q[i];
}
for(int i=0; i<t1; ++i) if(!q1[i].K) T::Modify_Range(q1[i].l,q1[i].r,-1);//q1→_→
for(int i=0; i<t1; ++i) q[h+i]=q1[i];
for(int i=0; i<t2; ++i) q[h+t1+i]=q2[i];
Solve(l,mid,h,h+t1-1), Solve(mid+1,r,h+t1,t);
} int main()
{
T::n=n=read(), m=read(); int tot=0;
for(int l,r,i=1; i<=m; ++i)
if(read()==1) l=read(), r=read(), q[i]=Operation(0,l,r,n-read());
else l=read(), r=read(), q[i]=Operation(readll(),l,r,++tot);
Solve(-N,N,1,m);
for(int i=1; i<=tot; ++i) printf("%d\n",n-Ans[i]); return 0;
}

线段树:(常数大的一匹)

//7320kb	6064ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 50000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=50005; int n,m,A[N],Ans[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Operation
{
LL K; int l,r,pos;//K!=0:Query [l,r] K; K=0:Add [l,r] pos.
Operation() {}
Operation(LL K,int l,int r,int p):K(K),l(l),r(r),pos(p) {}
}q[N],q1[N],q2[N]; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline LL readll()
{
LL now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
namespace T
{
#define lson rt<<1
#define rson rt<<1|1
#define ToL l,m,rt<<1
#define ToR m+1,r,rt<<1|1 LL sum[N<<2],tag[N<<2]; inline void Update(int rt){
sum[rt]=sum[lson]+sum[rson];
}
inline void PushDown(int rt,LL m)//long long!
{
tag[lson]+=tag[rt], tag[rson]+=tag[rt];
sum[lson]+=tag[rt]*(m-(m>>1)), sum[rson]+=tag[rt]*(m>>1);
tag[rt]=0;
}
void Modify(int l,int r,int rt,int L,int R,int v)
{
if(L<=l && r<=R)
tag[rt]+=v, sum[rt]+=1ll*(r-l+1)*v;
else
{
if(tag[rt]) PushDown(rt,r-l+1);
int m=l+r>>1;
if(L<=m) Modify(ToL,L,R,v);
if(m<R) Modify(ToR,L,R,v);
Update(rt);
}
}
LL Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return sum[rt];
if(tag[rt]) PushDown(rt,r-l+1);
int m=l+r>>1;
if(L<=m)
if(m<R) return Query(ToL,L,R)+Query(ToR,L,R);
else return Query(ToL,L,R);
return Query(ToR,L,R);
}
}
void Solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r){
for(int i=h; i<=t; ++i) if(q[i].K) Ans[q[i].pos]=l;
return;
}
bool goon=0;//无询问时直接return。
for(int i=h; i<=t; ++i) if(q[i].K) {goon=1; break;}
if(!goon) return; int mid=l+r>>1, t1=0, t2=0;
for(int i=h; i<=t; ++i)
if(q[i].K)
{
LL tmp=T::Query(1,n,1,q[i].l,q[i].r);
if(tmp>=q[i].K) q1[t1++]=q[i];
else q[i].K-=tmp, q2[t2++]=q[i];
}
else
{
if(q[i].pos<=mid) T::Modify(1,n,1,q[i].l,q[i].r,1), q1[t1++]=q[i];
else q2[t2++]=q[i];
}
for(int i=0; i<t1; ++i) if(!q1[i].K) T::Modify(1,n,1,q1[i].l,q1[i].r,-1);//q1→_→
for(int i=0; i<t1; ++i) q[h+i]=q1[i];
for(int i=0; i<t2; ++i) q[h+t1+i]=q2[i];
Solve(l,mid,h,h+t1-1), Solve(mid+1,r,h+t1,t);
} int main()
{
n=read(), m=read(); int tot=0;
for(int l,r,i=1; i<=m; ++i)
if(read()==1) l=read(), r=read(), q[i]=Operation(0,l,r,n-read());
else l=read(), r=read(), q[i]=Operation(readll(),l,r,++tot);
Solve(-N,N,1,m);
for(int i=1; i<=tot; ++i) printf("%d\n",n-Ans[i]); return 0;
}

线段树 标记永久化:WA了,不知道该怎么着。。(应该没问题啊)

//标记永久化替代PushDown可以减小常数,但是怎么不对exm?
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=50005; int n,m,A[N],Ans[N];
struct Operation
{
LL K; int l,r,pos;//K!=0:Query [l,r] K; K=0:Add [l,r] pos.
Operation() {}
Operation(LL K,int l,int r,int p):K(K),l(l),r(r),pos(p) {}
}q[N],q1[N],q2[N]; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline LL readll()
{
LL now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
namespace T
{
#define lson rt<<1
#define rson rt<<1|1
#define ToL l,m,rt<<1
#define ToR m+1,r,rt<<1|1 LL sum[N<<2],all[N<<2]; void Modify(int l,int r,int rt,int L,int R,int v)
{
sum[rt]+=1ll*v*(R-L+1);
if(L<=l && r<=R) all[rt]+=v;
else
{
int m=l+r>>1;
if(L<=m) Modify(ToL,L,m,v);
if(m<R) Modify(ToR,m+1,R,v);
}
}
LL Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return sum[rt];
int m=l+r>>1;
if(L<=m)
if(m<R) return 1ll*all[rt]*(R-L+1)+Query(ToL,L,R)+Query(ToR,L,R);
else return 1ll*all[rt]*(R-L+1)+Query(ToL,L,R);
return 1ll*all[rt]*(R-L+1)+Query(ToR,L,R);
}
}
void Solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r){
for(int i=h; i<=t; ++i) if(q[i].K) Ans[q[i].pos]=l;
return;
}
bool goon=0;//无询问时直接return。
for(int i=h; i<=t; ++i) if(q[i].K) {goon=1; break;}
if(!goon) return; int mid=l+r>>1, t1=0, t2=0;
for(int i=h; i<=t; ++i)
if(q[i].K)
{
LL tmp=T::Query(1,n,1,q[i].l,q[i].r);
if(tmp>=q[i].K) q1[t1++]=q[i];
else q[i].K-=tmp, q2[t2++]=q[i];
}
else
{
if(q[i].pos<=mid) T::Modify(1,n,1,q[i].l,q[i].r,1), q1[t1++]=q[i];
else q2[t2++]=q[i];
}
for(int i=0; i<t1; ++i) if(!q1[i].K) T::Modify(1,n,1,q1[i].l,q1[i].r,-1);//q1
for(int i=0; i<t1; ++i) q[h+i]=q1[i];
for(int i=0; i<t2; ++i) q[h+t1+i]=q2[i];
Solve(l,mid,h,h+t1-1), Solve(mid+1,r,h+t1,t);
} int main()
{
n=read(), m=read(); int tot=0;
for(int l,r,i=1; i<=m; ++i)
if(read()==1) l=read(), r=read(), q[i]=Operation(0,l,r,n-read());
else l=read(), r=read(), q[i]=Operation(readll(),l,r,++tot);
Solve(-N,N,1,m);
for(int i=1; i<=tot; ++i) printf("%d\n",n-Ans[i]); return 0;
}

BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)的更多相关文章

  1. BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

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

  2. BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

    [题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...

  3. BZOJ 3110 [ZJOI2013]K大数查询 (整体二分+线段树)

    和dynamic rankings这道题的思想一样 只不过是把树状数组换成线段树区间修改,求第$K$大的而不是第$K$小的 这道题还有负数,需要离散 #include <vector> # ...

  4. BZOJ 3110 [Zjoi2013]K大数查询(整体二分)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 11654  Solved: 3505[Submit][St ...

  5. BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Sta ...

  6. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  7. 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

    [原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Descri ...

  8. BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

    BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...

  9. BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 418   Solved: 235 [ Submit][ ...

随机推荐

  1. 使用TS+Sequelize实现更简洁的CRUD

    如果是经常使用Node来做服务端开发的童鞋,肯定不可避免的会操作数据库,做一些增删改查(CRUD,Create Read Update Delete)的操作,如果是一些简单的操作,类似定时脚本什么的, ...

  2. 键盘ASCII码

    回车键 -- CR 键0x0d   -- 16进制13 -- 10 进制'\r' -- 也可以 换行键 -- LF0x0a   -- 16进制10 -- 10 进制'\n' -- 也可以 esc键   ...

  3. c# 通过Windows服务启动外部程序

    1. 新建一个Windows服务应用程序 创建项目——>Visual C# 左侧的"+"——>Windows ——>Windows 服务(右侧模板)——>输 ...

  4. The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context,

    在iis7.0布署网站后运行的错误,大致意思是:数据保护操作是不成功的.这可能是由于没有为当前线程的用户加载用户配置文件的导致 解决办法: 先为自己的网站新建一个应用程序池,然后新建的应用程序池上右键 ...

  5. Runtime - Associated Objects (关联对象) 的实现原理

    主要围绕3个方面说明runtime-Associated Objects (关联对象) 1. 使用场景 2.如何使用 3.底层实现 3.1  实现原理 3.2 关联对象被存储在什么地方,是不是存放在被 ...

  6. redis从入门到放弃 -> 部署方案

    单点部署方案 环境准备: [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) [root@ ...

  7. vue实现结算淘宝购物车效果

    实现单选时的价格,全选时价格 单选效果图 全选效果图 html <template> <!-- 淘宝结算购物车 --> <div class="settleme ...

  8. 利用vw+rem实现移动web适配布局

    基本概念 1.单位 Px(CSS pixels) 像素 (px) 是一种绝对单位(absolute units), 因为无论其他相关的设置怎么变化,像素指定的值是不会变化的 其实是相对于某个设备而言的 ...

  9. 制作macOS10.12系列的系统镜像文件

    制作macOS10.12系列的系统镜像文件步骤,过程也比较简单,十来个命令.以10.12.6为例,首先,在苹果商店下载系统安装包APP,或者网上下载后把安装APP复制到  应用程序  文件夹. 然后打 ...

  10. IE手工导入证书

    打开cer文件->欢迎使用证书导入向导->下一步->将所有的证书放入下列存储->受信任的根证书颁发机构->完成