2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组,CDQ分治
TMD。。。这题卡内存卡的真优秀。。。
所以以后还是别用主席树的写法。。。不然怎么死的都不知道。。。
树套树中,主席树方法开权值线段树。。。会造成空间的浪费。。。这道题内存卡的很紧。。。
由于树套树已经不需要持久化了,直接动态开点就完事了。。。用主席树方法开过不去,要么超内存,要么越界。。。
大概思路。。。这题要求的[L,R]区间内,满足x<=a[i]<=y的连续的段数,
这题大概是个套路题,我们很容易想到,我们把连续的区间变成单点,把一段区间,类似1 1 1 3 5 变成 1 0 0 3 5 这样我们
只需要维护区间内部,在某个范围内数字的个数,这样的求法有个很显然的弊端如果1 0 0 3 5 序列, 我们求的区间是 2到5
这样求出来的答案是2,但是答案是3,究其原因,是我们b[l]端点出了问题,如果b[l]是0,我们求出来的就比答案少一个,那
么如何求出答案呢???很简单,可以先求出a[l+1]-a[r]的个数,这个算出来的是肯定不准确的,在b[l+1]=0的时候,在其他的
情况下正确的,如果b[l+1]=0 或者b[l+1]!=0,我们只要判断a[l]是否满足,如果满足条件就+1,这样就保证b[l+1]的情况,并且
在b[l+1]!=0的情况下,也是正确的。
考虑修改,单点更新,如果当前点是a[l]==a[l-1]那么a[l]将变成一个新的左端点。
如果修改后,a[l]==a[l+1]那么a[l+1]将不再是一个左端点,需要舍去。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxx = 2e5+;
struct node{
int l,r;
int cnt;
}tree[maxx*];
int cnt,n,cnt1,cnt2;
int root[maxx],a[maxx],trl[maxx],trr[maxx];
void inserts(int &now,int l,int r,int pos,int w){
if(!now)now=++cnt;
tree[now].cnt+=w;
if (l==r){
return ;
}
int mid=(l+r)>>;
if (pos<=mid){
inserts(tree[now].l,l,mid,pos,w);
}else{
inserts(tree[now].r,mid+,r,pos,w);
}
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int w){
for(int i=x;i<=n;i+=lowbit(i)){
inserts(root[i],,n,a[x],w);
}
}
int query(int l,int r,int ql,int qr){
if (r<ql || l>qr){
return ;
}
int tmpl[],tmpr[];
int s=,mid=(l+r)>>,sum=;
for(int i=;i<=cnt1;i++)s-=tree[trl[i]].cnt,tmpl[i]=trl[i];
for(int i=;i<=cnt2;i++)s+=tree[trr[i]].cnt,tmpr[i]=trr[i];
if (ql<=l && r<=qr){
return s;
}
if (mid>=ql){
for (int i=;i<=cnt1;i++){
trl[i]=tree[tmpl[i]].l;
}
for (int i=;i<=cnt2;i++){
trr[i]=tree[tmpr[i]].l;
}
sum+=query(l,mid,ql,qr);
}
if (mid<qr){
for (int i=;i<=cnt1;i++){
trl[i]=tree[tmpl[i]].r;
}
for (int i=;i<=cnt2;i++){
trr[i]=tree[tmpr[i]].r;
}
sum+=query(mid+,r,ql,qr);
}
return sum;
}
int main(){
int m;
scanf("%d%d",&n,&m);
cnt=cnt1=cnt2=;
for (int i=;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]!=a[i-])add(i,);
}
int op;
int pos,v,l,r,x,y;
while(m--){
scanf("%d",&op);
if(op==){
scanf("%d%d",&pos,&v);
if (a[pos]==v)continue;
if(a[pos]!=a[pos-]){
add(pos,-);
}
if(a[pos]==a[pos+]){
add(pos+,);
}else if (a[pos+]==v){
add(pos+,-);
}
a[pos]=v;
if (a[pos]!=a[pos-]){
add(pos,);
}
}else {
scanf("%d%d%d%d",&l,&r,&x,&y);
cnt1=cnt2=;
int f=;
for (int i=l;i;i-=lowbit(i)){
trl[++cnt1]=root[i];
}
for (int i=r;i;i-=lowbit(i)){
trr[++cnt2]=root[i];
}
if (a[l]>=x && a[l]<=y)f++;
printf("%d\n",query(,n,x,y)+f);
}
}
return ;
}
CDQ分治,分成三维偏序问题,第一维时间,也就是构造和询问顺序,第二维度坐标,第三维度值域,按照三维偏序,进行处理,把询问排序即可。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxx = 4e5+;
const int maxn=2e5+;
struct node{
int op,f,l,x,id;
///操作类型 增加值 位置 值域 答案编号
node(){}
node(int op,int f,int l,int x):op(op),f(f),l(l),x(x){};
node(int op,int f,int l,int x,int id):op(op),f(f),l(l),x(x),id(id){};
bool operator < (const node &s) const{
return l<s.l;
}
}q[maxx*];
int a[maxx];
int ans[maxx];
int sum[maxx];
int n;
///BIT部分
int lowbit(int x){
return x&(-x);
}
void add(int x,int w){
for (int i=x;i<=maxn;i+=lowbit(i)){
sum[i]+=w;
}
return ;
}
int getsum(int x){
int s=;
for (int i=x;i;i-=lowbit(i)){
s+=sum[i];
}
return s;
}
void cdq(int l,int r){
if (l==r){
return;
}
int mid=(l+r)>>;
cdq(l,mid);
cdq(mid+,r);
sort(q+l,q+mid+);
sort(q+mid+,q+r+);
int i=l,j=mid+;
while(i<=mid && j<=r){
///右边的操作对左边没有影响
if (q[j].op==){
j++;continue;
}
while(i<=mid && q[i].l<=q[j].l){
///左边的询问对右边没有影响
if (q[i].op==)add(q[i].x,q[i].f);
i++;
}
///查询小于等于q[j].x的个数,比乘以操作类型
ans[q[j].id]+=q[j].f*getsum(q[j].x);
j++;
}
while(j<=r){
if (q[j].op==){j++;continue;}
ans[q[j].id]+=q[j].f*getsum(q[j].x);
j++;
}
i=l,j=mid+;
/**清空**/
while(i<=mid && j<=r){
if (q[j].op==){
j++;
continue;
}
while(i<=mid && q[i].l<=q[j].l){
if (q[i].op==)add(q[i].x,-q[i].f);
i++;
}
j++;
}
}
int main(){
int m;
scanf("%d%d",&n,&m);
memset(ans,,sizeof(ans));
int tot=;
///当成插入
for (int i=;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]!=a[i-])q[++tot]=node(,,i,a[i]);
}
int pos,v,l,r,x,y,op;
int cnt=;
for (int i=;i<=m;i++){
scanf("%d",&op);
if (op==){
scanf("%d%d",&pos,&v);
if (a[pos]==v)continue;
///如果修改位置不等于前面一个,那么这个点是左端点,去掉需要在pos删除值a[pos]
if (a[pos]!=a[pos-]){
q[++tot]=node(,-,pos,a[pos]);
}
///如果当前值是等前面一个值的,那么当前位置修改后,后面一个值,变成左端点,所以+1
if (a[pos]==a[pos+]){
q[++tot]=node(,,pos+,a[pos+]);
///如果后一个位置和前面一个值不同,代表右边一个是左端点,但是如果加入的值是等于这个值,那么需要减去
}else if (a[pos+]==v){
q[++tot]=node(,-,pos+,a[pos+]);
}
a[pos]=v;
///修改以后,如果不等于前面一个值,那么还需要更新
if (a[pos]!=a[pos-])
q[++tot]=node(,,pos,a[pos]);
}else {
cnt++;
scanf("%d%d%d%d",&l,&r,&x,&y);
if (a[l]<=y && a[l]>=x){
ans[cnt]=;
}
l++;
if (l>r)continue;
///把二维区间询问拆出来
///询问<=r && <=y的个数
q[++tot]=node(2,1,r,y,cnt);
///询问<=y && <=l-1的个数
if (l>1)q[++tot]=node(2,-1,l-1,y,cnt);
///询问<=x-1 && <=r的个数
if (x>1)q[++tot]=node(2,-1,r,x-1,cnt);
///询问<=x-1 && <=l-1的个数
if (l>1 && l>1)q[++tot]=node(2,1,l-1,x-1,cnt);
}
}
cdq(,tot);
for (int i=;i<=cnt;i++){
cout<<ans[i]<<endl;
}
return ;
}
2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组,CDQ分治的更多相关文章
- 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)
题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...
- 2019 ICPC 南昌网络赛I:Yukino With Subinterval(CDQ分治)
Yukino With Subinterval Yukino has an array a_1, a_2 \cdots a_na1,a2⋯*a**n*. As a tsundere girl, Yuk ...
- 2019南昌网络赛-I(单调栈+线段树)
题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...
- ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval
ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...
- 2019南昌网络赛 I. Yukino With Subinterval 树状数组套线段树
I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...
- ACM-ICPC 2019南昌网络赛F题 Megumi With String
ACM-ICPC 南昌网络赛F题 Megumi With String 题目描述 给一个长度为\(l\)的字符串\(S\),和关于\(x\)的\(k\)次多项式\(G[x]\).当一个字符串\(str ...
- 2019南昌网络赛 hello 2019
这道题和一道2017,2016的类似. A string t is called nice if a string “2017” occurs in t as a subsequence but a ...
- 2019南昌网络赛G. tsy's number
题意:\(\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n\frac{\phi(i)*\phi(j^2)*\phi(k^3)}{\phi(i)*\phi(j)*\phi(k)} ...
- 2019南昌网络赛-M(二分)
题目链接:https://nanti.jisuanke.com/t/38232 题意:给定字符串s(长度<=1e5),然后N组样例(N<=1e5),每组输入一个字符串t判断t是否为s的字串 ...
随机推荐
- Python发送QQ消息
一.需求背景 每天早上取一批数据,数据文件经过压缩加密之后用邮箱发送,而解压密码通过QQ发送给运营.使用Python进行取数.文件加密在已经实现的情况下,需要实现通过QQ发送密码的功能. 在进 ...
- JAVA数据库连接池的革命 -- 从BoneCP到HikariCP(转)
从BoneCP到HikariCP 今天笔者本想更新一下项目中使用到的BoneCP版本的.却无意发现jolbox网站打不开了.起初以为是被墙掉了,经过一番查找,居然在BoneCP的Github站看到了如 ...
- python基础--递归、三元表达式、列表(字典)生成式、匿名函数、常用的内置函数
函数的递归:函数在调用阶段直接或者间接的又调用自身 递归的两个阶段: 1.回溯:就是一次次重复的过程,这个重复的过程必须建立在每一次重复问题的复杂度都是应该下降的,直接有一个最终的结束条件(这个结束条 ...
- day36 07-Hibernate抓取策略:many-to-one上的抓取策略
package cn.itcast.test; import java.util.List; import org.hibernate.Hibernate; import org.hibernate. ...
- vmstat-虚拟内存查看实例
虚拟内存运行原理 在系统中运行的每个进程都需要使用到内存,但不是每个进程都需要每时每刻使用系统分配的内存空间.当系统运行所需内存超过实际的物理内存,内核会释放某些进程所占用但未使用的部分或所有物理内存 ...
- ZOJ3195 Design the city [2017年6月计划 树上问题04]
Design the city Time Limit: 1 Second Memory Limit: 32768 KB Cerror is the mayor of city HangZho ...
- oracle -视图 序列 约束
1.视图 视图是基于一个或者多个表数据库对象,视图允许用户创建一个无数据的”伪表“,视图只是一个获取特定列好行的sql查询组成,通过视图检索数据就像从表中检索数据 一样. 视图可以提供一个附加的安全层 ...
- 六.随机神经网络Boltzmann(玻尔兹曼机)
Hopfield网络具有最优计算功能,然而网络只能严格按照能量函数递减方式演化,很难避免伪状态的出现,且权值容易陷入局部极小值,无法收敛于全局最优解. 如果反馈神经网络的迭代过程不是那么死板,可以在一 ...
- 替换文本:将文本文件中的所有src替换为dst
题意: 将文本文件中的所有src替换为dst 方法一:使用String import java.io.File; import java.io.FileNotFoundException; impor ...
- 使用Redis管道提升性能
首发于 樊浩柏科学院 Redis 的 管道 (pipelining)是用来打包多条无关命令批量执行,以减少多个命令分别执行带来的网络交互时间.在一些批量操作数据的场景,使用管道可以显著提升 Redis ...