bzoj 3110 [Zjoi2013]K大数查询【树套树||整体二分】
树套树:
约等于是个暴力了。以区间线段树的方式开一棵权值线段树,在权值线段树的每一个点上以动态开点的方式开一棵区间线段树。
结果非常惨烈(时限20s)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=23000005,M=500005;
int n,m,tot,rt[M],sz,lz[N];
long long sum[N],mp[M];
struct data
{
int l,r;
}tr[N];
struct node
{
int a,b,op;
long long c;
}ans[M];
int find(long long x)
{
return lower_bound(mp+1,mp+tot+1,x)-mp-1;
}
void pushdown(int x,int l,int r)
{
int mid=(l+r)/2;
if(!tr[x].l)
tr[x].l=++sz;
if(!tr[x].r)
tr[x].r=++sz;
int a=tr[x].l,b=tr[x].r;
lz[a]+=lz[x];
lz[b]+=lz[x];
sum[a]+=(long long)(mid-l+1)*(long long)lz[x];
sum[b]+=(long long)(r-mid)*(long long)lz[x];
lz[x]=0;
}
void change(int &ro,int l,int r,int ll,int rr)
{
if(!ro)
ro=++sz;
if(lz[ro])
pushdown(ro,l,r);
if(l>=ll&&r<=rr)
{
sum[ro]+=(long long)(r-l+1);
lz[ro]++;
return;
}
int mid=(l+r)/2;
if(ll<=mid)
change(tr[ro].l,l,mid,ll,rr);
if(rr>mid)
change(tr[ro].r,mid+1,r,ll,rr);
sum[ro]=(long long)sum[tr[ro].l]+sum[tr[ro].r];
}
void update(int a,int b,int c,int now,int l,int r)
{
change(rt[now],1,n,a,b);
if(l==r)
return;
int mid=(l+r)/2;
if(c<=mid)
update(a,b,c,now<<1,l,mid);
else
update(a,b,c,now<<1|1,mid+1,r);
}
long long query(int k,int l,int r,int ll,int rr)
{
if(lz[k])
pushdown(k,l,r);
if (l>=ll&&r<=rr)
return sum[k];
int mid=(l+r)/2;
long long ans=0;
if(ll<=mid)
ans+=query(tr[k].l,l,mid,ll,rr);
if(rr>mid)
ans+=query(tr[k].r,mid+1,r,ll,rr);
return ans;
}
int ques(int a,int b,long long c)
{
int l=1,r=tot,k=1;
while(l!=r)
{
int mid=(l+r)>>1;
long long t=query(rt[k<<1],1,n,a,b);
if(t>=c)
r=mid,k<<=1;
else
l=mid+1,k=k<<1|1,c-=(long long)t;
}
return l;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d%lld",&ans[i].op,&ans[i].a,&ans[i].b,&ans[i].c);
if(ans[i].op==1)
mp[++tot]=ans[i].c;
}
sort(mp+1,mp+tot+1);
tot=unique(mp+1,mp+tot+1)-mp-1;
for(int i=1;i<=m;i++)
if(ans[i].op==1)
{
int k=find(ans[i].c)+1;
update(ans[i].a,ans[i].b,k,1,1,tot);
}
else
{
long long cnt=query(rt[1],1,n,ans[i].a,ans[i].b);
printf("%lld\n",mp[ques(ans[i].a,ans[i].b,cnt-ans[i].c+1)]);
}
return 0;
}
整体二分
首先我一开始没有注意到的:
1操作中abs(c)<=N
2操作中c<=Maxlongint
也就是说答案在0到n之间,那么久可以整体二分来做了
维护一棵区间线段树,维护区间加标记和区间清零标记。
每次操作前清零
设当前答案区间为[l,r],询问区间为[x,y],mid=(l+r)>>1;
对于插入操作:如果插入的数>mid,就在其区间上+1,放到前一堆(我不知道怎么形容了,否则不操作,放倒后一堆;
对于查询操作:如果查询区间内的数符合k个要求,放到前一堆,否则放到后一堆。
直到l==r,更新[x,y]内的答案
写丑了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=500005;
int n,m,ans[N];
long long sum[N*4],lz[N*4],tg[N*4];
struct qwe
{
int l,r,id,n,p,x;
}a[N];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void clear(int now)
{
sum[now]=lz[now]=0;
tg[now]=1;
}
bool cmp(const qwe &a,const qwe &b)
{
return a.n<b.n;
}
void pd(int now,int l,int r)
{
if(tg[now])
{
clear(now<<1);
clear(now<<1|1);
tg[now]=0;
}
int mid=(l+r)/2;
if(lz[now])
{
lz[now<<1]+=lz[now];
lz[now<<1|1]+=lz[now];
sum[now<<1]+=lz[now]*(mid-l+1);
sum[now<<1|1]+=lz[now]*(r-mid);
lz[now]=0;
}
}
void ud(int now)
{
sum[now]=sum[now<<1]+sum[now<<1|1];
}
void update(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
{
sum[now]+=(r-l+1);
lz[now]++;
return;
}
int mid=(l+r)/2;
pd(now,l,r);
if(ll<=mid)
update(now<<1,l,mid,ll,rr);
if(rr>mid)
update(now<<1|1,mid+1,r,ll,rr);
ud(now);
}
long long ques(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return sum[now];
int mid=(l+r)/2;
pd(now,l,r);
long long ans=0;
if(ll<=mid)
ans+=ques(now<<1,l,mid,ll,rr);
if(rr>mid)
ans+=ques(now<<1|1,mid+1,r,ll,rr);
return ans;
}
void erfen(int l,int r,int x,int y)
{
if(l==r)
{
for(int i=x;i<=y;i++)
if(a[i].p==2)
ans[a[i].id]=l;
return;
}
int mid=(l+r)/2,pl=0,pr=y-x+1;
clear(1);
for(int i=x;i<=y;i++)
if(a[i].p==1)
{
if(a[i].x<=mid)
a[i].n=++pl;
else
{
update(1,1,n,a[i].l,a[i].r);
a[i].n=++pr;
}
}
else
{
long long t=ques(1,1,n,a[i].l,a[i].r);
if(t>=a[i].x)
a[i].n=++pr;
else
{
a[i].x=a[i].x-t;
a[i].n=++pl;
}
}
sort(a+x,a+y+1,cmp);
erfen(l,mid,x,x+pl-1);
erfen(mid+1,r,x+pl,y);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
a[i].p=read(),a[i].l=read(),a[i].r=read(),a[i].x=read(),a[i].id=i;
erfen(0,n,1,m);
for(int i=1;i<=m;i++)
if(ans[i])
printf("%d\n",ans[i]);
return 0;
}
bzoj 3110 [Zjoi2013]K大数查询【树套树||整体二分】的更多相关文章
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )
BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ---------------------------------------------------- ...
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 418 Solved: 235 [ Submit][ ...
- BZOJ 3110 [Zjoi2013]K大数查询(整体二分)
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 11654 Solved: 3505[Submit][St ...
- BZOJ 3110 [Zjoi2013]K大数查询 ——树套树
[题目分析] 外层区间线段树,内层是动态开点的权值线段树. SY神犇说树套树注重的是内外层的数据结构的选择问题,果然很重要啊. 动态开点的实现方法很好. [代码] #include <cstdi ...
- BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]
有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. N ...
- [BZOJ 3110] [Zjoi2013] K大数查询 【树套树】
题目链接: BZOJ - 3110 题目分析 这道题是一道树套树的典型题目,我们使用线段树套线段树,一层是区间线段树,一层是权值线段树.一般的思路是外层用区间线段树,内层用权值线段树,但是这样貌似会很 ...
随机推荐
- HDU——1054 Strategic Game
Strategic Game Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 一起talk C栗子吧(第一百回:C语言实例--使用信号量进行进程间同步与相互排斥一)
各位看官们.大家好,上一回中咱们说的是进程间同步与相互排斥的样例,这一回咱们说的样例是:使用信号量进行进程间同步与相互排斥. 闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,信号量是由著名 ...
- Office EXCEL 中如何让一个单元格的数据链接到另一个工作表的数据
比如我在Sheet2中定义了几个数据,这些都是简单的数字,而在Sheet1中让要被绑定的单元格等于Sheet2的对应单元格地址(比如Sheet2!B1,Sheet2!B2之类的) 然后就可以一改全 ...
- vue 获取当前时间 格式YYYY-MM-DD
函数封装: /** * 获取当前时间 * 格式YYYY-MM-DD */ Vue.prototype.getNowFormatDate = function() { var date = new Da ...
- Linux OpenSSH后门的加入与防范
引言:相对于Windows,Linux操作系统的password较难获取.只是非常多Linuxserver配置了OpenSSH服务.在获取root权限的情况下,能够通过改动或者更新OpenSSH代码等 ...
- [原创+分享]Mandelbrot Explorer
Mandelbrot Explorer 是一款用于在MandelBort集/Julia集上进行无限漫游的软件,使用VS2013+CUDA6.5开发而成.它也是我学习CUDA开发的一个小小的成果,欢迎大 ...
- Jenkins系列之-—02 email-ext 邮件模板
邮件通知配置 系统管理 → 系统设置 → 邮件通知 SMTP 服务器:配置 SMTP 服务器.(不填默认本地运行服务器) 用户默认邮件后缀:注册用户邮件只需填写用户名即可,后缀会加该后缀,如果填写,则 ...
- vue 配置跨域访问
主要在config->index.js中配置 proxyTable: { ‘/gameapi’: { changeOrigin: true, // target: ‘http://rap.id. ...
- POJ 1061 青蛙的约会(扩展GCD求模线性方程)
题目地址:POJ 1061 扩展GCD好难懂.. 看了半天.最终把证明什么的都看明确了. .推荐一篇博客吧(戳这里),讲的真心不错.. 直接上代码: #include <iostream> ...
- IO流(字节流复制)01
package ioDemo; import java.io.*; /** * IO流(字节流复制) * Created by lcj on 2017/11/2. */ public class bu ...