COGS.1822.[AHOI2013]作业(莫队 树状数组/分块)
题目链接: COGS、BZOJ3236
Upd: 树状数组实现的是单点加 区间求和,采用值域分块可以\(O(1)\)修改\(O(sqrt(n))\)查询。同BZOJ3809.
莫队为\(O(n^{1.5})\)次修改和\(O(n)\)次查询。
注意这两个需求并不平衡,所以在搭配数据结构时常使用分块而不是线段树。
(转自莫队复杂度分析 by Meiku Kazami)
1.莫队+树状数组
/*
每个[l,r]的询问中又多了[a,b]值的限制。原先now是所有种类的个数,所以用 莫队+树状数组做
两问,维护两个树状数组
O(m*sqrt(n)*logn)
*/
#include<cmath>
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=1e6+5;
int n,m,size,A[N],t1[N],t2[N],times[N],Ans1[M],Ans2[M];
struct Ques
{
int l,r,a,b,id;
bool operator <(const Ques &x)const
{
return l/size==x.l/size ? r<x.r : l/size<x.l/size;
}
}q[M];
inline int read()
{
int now=0,f=1;register char c=getchar();
for(;!isdigit(c);c=getchar())
if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=getchar());
return now*f;
}
inline int lb(int x)
{
return x&-x;
}
void Update(int p,int v,int *t)
{
while(p<=n)
t[p]+=v, p+=lb(p);
}
int Query(int p,int *t)
{
int res=0;
while(p)
res+=t[p], p-=lb(p);
return res;
}
void Add(int p)
{
Update(A[p],1,t1);
if(!times[A[p]]) Update(A[p],1,t2);
++times[A[p]];
}
void Subd(int p)
{
Update(A[p],-1,t1);
--times[A[p]];
if(!times[A[p]]) Update(A[p],-1,t2);
}
int main()
{
freopen("ahoi2013_homework.in","r",stdin);
freopen("ahoi2013_homework.out","w",stdout);
n=read(),m=read();
size=sqrt(n);
for(int i=1;i<=n;++i)
A[i]=read();
for(int i=1;i<=m;++i)
q[i].l=read(), q[i].r=read(), q[i].a=read(), q[i].b=read(), q[i].id=i;
sort(q+1,q+1+m);
for(int l=1,r=0,i=1;i<=m;++i)
{
int ln=q[i].l,rn=q[i].r;
while(l<ln) Subd(l++);
while(l>ln) Add(--l);
while(r<rn) Add(++r);
while(r>rn) Subd(r--);
Ans1[q[i].id]=Query(q[i].b,t1)-Query(q[i].a-1,t1),//注意值的区间是[a,b]不是[l,r]
Ans2[q[i].id]=Query(q[i].b,t2)-Query(q[i].a-1,t2);
// printf("%d:%d %d ans1:%d ans2:%d\n",q[i].id,ln,rn,Ans1[q[i].id],Ans2[q[i].id]);
}
for(int i=1;i<=m;++i)
printf("%d %d\n",Ans1[i],Ans2[i]);
fclose(stdin);fclose(stdout);
return 0;
}
2.莫队+值域分块
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5,MAXIN=2e6;
int n,m,size,Ans1[N*10],Ans2[N*10],A[N],tm[N],bel[N],sum1[500],sum2[500];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Ask
{
int l,r,a,b,id;
bool operator <(const Ask &a)const
{
return l/size==a.l/size ? r<a.r : l/size<a.l/size;//更快 WTF
// return l/size==a.l/size?((l-1)/size&1 ? r>a.r : r<a.r):l/size<a.l/size;
}
}q[N*10];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Query(int *s,int l,int r,bool f)
{
int res=0,tmp=std::min(r,bel[l]*size);
for(int i=l; i<=tmp; ++i) res+= f?(tm[i]>0):tm[i];
if(bel[l]!=bel[r])
for(int i=(bel[r]-1)*size+1; i<=r; ++i)
res+= f?(tm[i]>0):tm[i];
for(int i=bel[l]+1; i<bel[r]; ++i) res+=s[i];
return res;
}
void Add(int p)
{
if(++tm[p]==1) ++sum2[bel[p]];
++sum1[bel[p]];
}
void Subd(int p)
{
if(!--tm[p]) --sum2[bel[p]];
--sum1[bel[p]];
}
int main()
{
n=read(), m=read(), size=sqrt(n);;//size=n/sqrt(m*2/3) //也没有更快 数组大小还要注意
for(int i=1; i<=n; ++i) bel[i]=(i-1)/size+1, A[i]=read();
for(int i=1; i<=m; ++i) q[i].l=read(),q[i].r=read(),q[i].a=read(),q[i].b=read(),q[i].id=i;
std::sort(q+1,q+1+m);
for(int l=1,r=0,ln,rn,i=1; i<=m; ++i)
{
int ln=q[i].l,rn=q[i].r;
while(l<ln) Subd(A[l++]);
while(l>ln) Add(A[--l]);
while(r<rn) Add(A[++r]);
while(r>rn) Subd(A[r--]);
Ans1[q[i].id]=Query(sum1,q[i].a,q[i].b,0), Ans2[q[i].id]=Query(sum2,q[i].a,q[i].b,1);
}
for(int i=1; i<=m; ++i) printf("%d %d\n",Ans1[i],Ans2[i]);
return 0;
}
COGS.1822.[AHOI2013]作业(莫队 树状数组/分块)的更多相关文章
- BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块
题目描述 输入 输出 样例输入 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 样例输出 2 2 1 1 3 2 2 1 提示 N=100000,M=1000000 ...
- BZOJ 3236: [Ahoi2013]作业(莫队+树状数组)
传送门 解题思路 莫队+树状数组.把求\([a,b]\)搞成前缀和形式,剩下的比较裸吧,用\(cnt\)记一下数字出现次数.时间复杂度\(O(msqrt(n)log(n)\),莫名其妙过了. 代码 # ...
- [AHOI2013]作业 莫队 树状数组
#include<cmath> #include<cstdio> #include<algorithm> #include<string> #inclu ...
- bzoj3236 作业 莫队+树状数组
莫队+树状数组 #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...
- BZOJ 3236 AHOI 2013 作业 莫队+树状数组
BZOJ 3236 AHOI 2013 作业 内存限制:512 MiB 时间限制:10000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目大意: 此时己是凌晨两点,刚刚做了Co ...
- BZOJ_3289_Mato的文件管理_莫队+树状数组
BZOJ_3289_Mato的文件管理_莫队+树状数组 Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号 .为了防止他人 ...
- bzoj 3289: Mato的文件管理 莫队+树状数组
3289: Mato的文件管理 Time Limit: 40 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Mato同学 ...
- 51nod 1290 Counting Diff Pairs | 莫队 树状数组
51nod 1290 Counting Diff Pairs | 莫队 树状数组 题面 一个长度为N的正整数数组A,给出一个数K以及Q个查询,每个查询包含2个数l和r,对于每个查询输出从A[i]到A[ ...
- 【BZOJ3460】Jc的宿舍(树上莫队+树状数组)
点此看题面 大致题意: 一棵树,每个节点有一个人,他打水需要\(T_i\)的时间,每次询问两点之间所有人去打水的最小等待时间. 伪·强制在线 这题看似强制在线,但实际上,\(pre\ mod\ 2\) ...
随机推荐
- passwd: Have exhausted maximum number of retries for service【转】
使用命令passwd修改密码时,遇到如下问题: # echo 'utf8'|passwd zhangsan --stdin Changing password for user zhangsan. p ...
- C# 实现UDP打洞通信(一)
最近研究了一下网络打洞的相关技术,TCP的方式据说可行性不高,各种困难,因此决定采用UDP(UDP是什么就不解释了)的方式. 原理: 我们都知道局域网内的主机想要访问外网的服务器是比较容易的,比如浏览 ...
- ajax post 传参数加引号和不加引号的区别
1.前言 用ajax技术,type:post,data:参数列表.参数列表就是一个JSON数据,但key可以加引号,也可以不加引号,那总有区别的. 2.区别 var d2 = "two&qu ...
- 基于python的k-s值计算
做评分卡模型时(假设有多个自变量,因变量即是否违约.)通常需要筛选变量. k-s值的作用类似于AUC,它期初是用来评价模型(变量)对是否违约事件的区分程度的. # -*- coding: utf-8 ...
- sklearn调参(验证曲线,可视化不同参数下交叉验证得分)
一 . 原始方法: 思路: 1. 参数从 0+∞ 的一个 区间 取点, 方法如: np.logspace(-10, 0, 10) , np.logspace(-6, -1, 5) 2. 循环调用cr ...
- JS的浅拷贝与深拷贝
浅拷贝 //这样的拷贝有一个问题.那就是,如果父对象的属性等于数组或另一个对象,//那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能. function exten ...
- OCM_第十八天课程:Section8 —》RAC 数据库 _ RAC DB 搭建/RAC DB 配置使用
注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...
- bootstrap----几个插件网址
1.SweetAlert (弹出框):https://github.com/t4t5/sweetalert 2.SweetAlert2 (弹出框):https://github.com/limonte ...
- Luogu P4944 【PION贪吃蛇】
简单模拟题 用一个数据结构存储这条蛇 考虑蛇的移动 1,如果死了,就把整个蛇清空,所有位置标记为食物 2,如果吃了东西,把这个位置更新为蛇头 3,如果正常走路,这个位置设为蛇头,同时删掉尾巴 蛇的存储 ...
- 有关Math数学运算的js函数
随机函数; Moth.random() //3.以下通过循环给数组每个元素赋值,随机数. // Math.random(); 可以随机0~1之间的任意数 [0,1) // alert(Math. ...