[BZOJ3236][AHOI2013]作业:树套树/莫队+分块
分析
第一问随便搞,直接说第二问。
令原数列为\(seq\),\(pre_i\)为\(seq_i\)这个值上一个出现的位置,于是可以简化询问条件为:
\(l \leq i \leq r\)
\(a \leq seq_i \leq b\)
\(pre_i < l\)
这是一个显然的三维数点问题。发现第三维\(pre_i\)只有最大值的限制,所以我们可以把所有询问按\(l\)升序排序,所有点按\(pre_i\)升序排序,用一个指针从左往右扫所有询问,然后不断向数据结构插入符合第三维要求的点,剩下的两维树状数组套权值线段树解决。
然后就被卡空间了。
然后题解告诉我们可以莫队+分块解决。
(这里因为修改次数远大于询问次数所以使用分块而非树状数组。)
\(FAQ\)
代码
树套树(MLE)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define lowbit(x) ((x)&(-(x)))
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,x) for(int i=head[(x)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=100005;
const int MAXM=1000005;
int n,m,siz,tot,a[MAXN],b[MAXN],pre[MAXN],las[MAXN];
int ans1[MAXM],ans2[MAXM];
int loc,ql,qr,root[MAXN],lc[MAXN*__],rc[MAXN*__],sum[MAXN*__];//FAQ
struct Po{
int pos,val,pre;
inline friend bool operator < (Po x,Po y){return x.pre<y.pre;}
}p[MAXN];
struct Qu{
int l,r,a,b,id;
inline friend bool operator < (Qu x,Qu y){return x.l<y.l;}
}q[MAXM];
#define mid ((l+r)>>1)
int upd(int pre,int l,int r){
int o=++tot;lc[o]=lc[pre],rc[o]=rc[pre],sum[o]=sum[pre]+1;
if(l==r) return o;
if(loc<=mid) lc[o]=upd(lc[pre],l,mid);
else rc[o]=upd(rc[pre],mid+1,r);
return o;
}
int query(int o,int l,int r){
if(ql>qr) return 0;
if(ql<=l&&r<=qr) return sum[o];
int ret=0;
if(mid>=ql) ret+=query(lc[o],l,mid);
if(mid<qr) ret+=query(rc[o],mid+1,r);
return ret;
}
int query(int u,int v,int l,int r){
if(ql>qr) return 0;
if(ql<=l&&r<=qr) return sum[v]-sum[u];
int ret=0;
if(mid>=ql) ret+=query(lc[u],lc[v],l,mid);
if(mid<qr) ret+=query(rc[u],rc[v],mid+1,r);
return ret;
}
#undef mid
inline void Add(int pos,int val){
loc=val;
for(int i=pos;i<=n;i+=lowbit(i)) root[i]=upd(root[i],1,siz);
}
inline int Ask(int x){
if(ql>qr) return 0;
int ret=0;
for(int i=x;i;i-=lowbit(i)) ret+=query(root[i],1,siz);
return ret;
}
inline int Ask(int l,int r,int lval,int rval){
ql=lval,qr=rval;
if(ql>qr) return 0;
return Ask(r)-Ask(l-1);
}
int main(){
n=read(),m=read();
rin(i,1,n) b[i]=a[i]=read();
std::sort(b+1,b+n+1);
siz=std::unique(b+1,b+n+1)-b-1;
rin(i,1,n) a[i]=std::lower_bound(b+1,b+siz+1,a[i])-b;
rin(i,1,n){pre[i]=las[a[i]];las[a[i]]=i;p[i]=(Po){i,a[i],pre[i]};}
rin(i,1,m){q[i].l=read(),q[i].r=read(),q[i].a=std::lower_bound(b+1,b+siz+1,read())-b,q[i].b=std::upper_bound(b+1,b+siz+1,read())-b-1,q[i].id=i;}
rin(i,1,n){loc=a[i];root[i]=upd(root[i-1],1,siz);}
rin(i,1,m){ql=q[i].a,qr=q[i].b;ans1[i]=query(root[q[i].l-1],root[q[i].r],1,siz);}
tot=0;memset(root,0,sizeof root);std::sort(p+1,p+n+1);std::sort(q+1,q+m+1);
int pptr=1,qptr=1;
while(pptr<=n&&!p[pptr].pre){Add(p[pptr].pos,p[pptr].val);pptr++;}
rin(i,1,n){
while(qptr<=m&&q[qptr].l==i){ans2[q[qptr].id]=Ask(q[qptr].l,q[qptr].r,q[qptr].a,q[qptr].b);qptr++;}
while(pptr<=n&&p[pptr].pre==i){Add(p[pptr].pos,p[pptr].val);pptr++;}
}
rin(i,1,m) printf("%d %d\n",ans1[i],ans2[i]);
return 0;
}
莫队+分块
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=100005;
const int MAXM=1000005;
const int SIZE=345;
int n,m,siz,ret1,ret2,a[MAXN],b[MAXN],blg[MAXN],cnt[MAXN],sum1[SIZE],sum2[SIZE],ans1[MAXM],ans2[MAXM];
struct Qu{
int l,r,lk,a,b,id;
inline friend bool operator < (Qu x,Qu y){
if(x.lk!=y.lk) return x.lk<y.lk;
if(x.lk&1) return x.r<y.r;
else return x.r>y.r;
}
}q[MAXM];
inline void query(int l,int r){
ret1=ret2=0;
rin(i,blg[l]+1,blg[r]-1) ret1+=sum1[i],ret2+=sum2[i];
int lim=std::min(blg[l]*SIZE,r);rin(i,l,lim) ret1+=cnt[i],ret2+=(cnt[i]>0);
if(blg[l]!=blg[r]) rin(i,(blg[r]-1)*SIZE+1,r) ret1+=cnt[i],ret2+=(cnt[i]>0);
}
int main(){
n=read(),m=read();
rin(i,1,n) a[i]=b[i]=read();
std::sort(b+1,b+n+1);siz=std::unique(b+1,b+n+1)-b-1;
rin(i,1,n){a[i]=std::lower_bound(b+1,b+siz+1,a[i])-b;blg[i]=(i-1)/SIZE+1;};
rin(i,1,m){q[i].l=read(),q[i].r=read(),q[i].a=std::lower_bound(b+1,b+siz+1,read())-b,q[i].b=std::upper_bound(b+1,b+siz+1,read())-b-1,q[i].lk=(q[i].l-1)/SIZE+1;q[i].id=i;}
std::sort(q+1,q+m+1);
int l=1,r=0;
rin(i,1,m){
if(q[i].a>q[i].b) continue;
while(l>q[i].l){l--;cnt[a[l]]++;sum1[blg[a[l]]]++;if(cnt[a[l]]==1)sum2[blg[a[l]]]++;}
while(r<q[i].r){r++;cnt[a[r]]++;sum1[blg[a[r]]]++;if(cnt[a[r]]==1)sum2[blg[a[r]]]++;}
while(l<q[i].l){cnt[a[l]]--;sum1[blg[a[l]]]--;if(cnt[a[l]]==0)sum2[blg[a[l]]]--;l++;}
while(r>q[i].r){cnt[a[r]]--;sum1[blg[a[r]]]--;if(cnt[a[r]]==0)sum2[blg[a[r]]]--;r--;}
query(q[i].a,q[i].b);ans1[q[i].id]=ret1;ans2[q[i].id]=ret2;
}
rin(i,1,m) printf("%d %d\n",ans1[i],ans2[i]);
return 0;
}
[BZOJ3236][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] 作业 && [BZOJ 3809] 【莫队(+分块)】
题目链接: BZOJ - 3236 BZOJ - 3809 算法一:莫队 首先,单纯的莫队算法是很好想的,就是用普通的第一关键字为 l 所在块,第二关键字为 r 的莫队. 这样每次端点移动添加或删 ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
- 「洛谷1903」「BZOJ2120」「国家集训队」数颜色【带修莫队,树套树】
题目链接 [BZOJ传送门] [洛谷传送门] 题目大意 单点修改,区间查询有多少种数字. 解法1--树套树 可以直接暴力树套树,我比较懒,不想写. 稍微口胡一下,可以直接来一个树状数组套主席树,也就是 ...
- NOI模拟 颜色 - 带修莫队/树套树
题意: 一个颜色序列,\(a_1, a_2, ...a_i\)表示第i个的颜色,给出每种颜色的美丽度\(w_i\),定义一段颜色的美丽值为该段颜色的美丽值之和(重复的只计算一次),每次都会修改某个位置 ...
- Tulip Festival(线段树+二分+CDQ+带修改莫队+树套树)
题目链接 传送门 线段树\(+\)二分思路 思路 比赛看到这题时感觉是一棵线段树\(+\)主席树,然后因为不会带修改主席树就放弃了,最后发现还卡了树套树. 由于本题数据保证序列中相同的数字不会超过20 ...
- 洛谷P4396 [AHOI2013]作业(树套树)
题意 题目链接 Sol 为什么一堆分块呀..三维数点不应该是套路离线/可持久化+树套树么.. 亲测树状数组套权值线段树可过 复杂度\(O(nlog^2n)\),空间\(O(nlogn)\)(离线) # ...
- BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块
BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块 Description Autumn和Bakser又在研究Gty的妹子序列了 ...
- [AHOI2013]作业 (莫队+分块)
[AHOI2013]作业 (莫队+分块) 题面 给定了一个长度为n的数列和若干个询问,每个询问是关于数列的区间[l,r],首先你要统计该区间内大于等于a,小于等于b的数的个数,其次是所有大于等于a,小 ...
随机推荐
- Fabric CA/数字证书管理
MSP(Membership Service Provider)成员管理服务提供商 名词: 1.CSR(Cerificate Signing Request):证书签署请求文件 CSR里包含申请者的 ...
- 2019CSP-S游记(?)
认识我的人都知道,我懒得写算法和模拟赛的博客,但是游记就不一样了,它比较好玩. Day0 中午随便收拾了下就坐高铁出发了,一个小时左右就到南昌了,随后坐公交,再步行到宾馆安置(也没多远). 宾馆离学校 ...
- JAVA日期时间相关库
Java的日期时间库比较乱,同样一个Date在java.sql下定义,同时也在java.util下也定义了一遍,真不知道SUN是怎么想的. java8以后,java通过jsr310标准引入了一套符合I ...
- SparkStreaming DStream转换
1.无状态转换操作 (1)无状态转化操作就是把简单的RDD转化操作应用到每个批次上,也就是转换DStream中的每一个RDD. 部分无状态转化操作: (2)尽管这些函数韩起来像作用在整个流上一样,但事 ...
- Linux部署项目 shell脚本启动 及 Centos7开放指定端口
我们首先要在linux上安装好jdk tomcat mysql 这些基本环境,这些可以在楼主的 Linux入门 里面找到. linux部署spring项目 1. 右击项目,maven ...
- 修改admin中App的名称与表的名称
修改APP的名称: # coding:utf-8 from django.apps import AppConfig import os default_app_config = 'repositor ...
- python学习笔记(4)
第六章 字符串操作 1.字符串处理 (1)字符串字 spam='Say hi to Bob\' s mother 面量 python中输入字符串:以单引号开始和结束 (2)双引号:字符串可以用双引号开 ...
- C语言scanf的返回值
#include <stdio.h> int main(void) { long num; long sum = 0L; int status; printf("Please e ...
- css隐藏滚动条 兼容谷歌、火狐、IE等各个浏览器
项目中,页面效果需要展示一个页面的移动端效果,使用的是一个苹果手机样式背景图,咋也没用过苹果,咋也不敢形容. 如下图所示: 在谷歌浏览器如图一滚动条顺利隐藏,但是火狐就如图二了,有了滚动条丑的一批. ...
- java交换两个变量值a,b的多钟方法
首先我们定义两个变量用来检查方法可行性 int a=5; int b=3; 方法一,也是最容易想到的,就是建立中间变量法 int temp; temp=a; a=b; b=temp; System.o ...