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的字串 ...
随机推荐
- spring的基于xml的AOP配置案例和切入点表达式的一些写法
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- JSP内置对象解析
out对象:(PrintWriter类的实例) 用来向客户端输出信息,除了输出各种信息外还负责对缓冲区进行管理: 主要方法: print / println void 输出数据 newLine() v ...
- 【Django入坑之路】Models操作
1:字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...
- os模块和sys模块
1.os模块与path有关:os.path.isfile():判断置顶对象是否为文件,是返回True,否返回Falseos.path.isdir():判断指定对象是否为目录,是返回True,否返回Fa ...
- OpenLayers在地图外放置控件
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...
- 强力Django+杀手级xadmin开发在线教育网站
强力Django+杀手级xadmin开发在线教育网站采用 Python3.7全新开发 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的 ...
- Spring_JDBC连接
1.导入jarbao 2.创建pojo,dao,Impl package com.tanlei.pojo; public class Department { private Long deptId; ...
- 通过IP地址訪问Jbossserver上的应用
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/liu765023051/article/details/28882533 环境介绍 Web项目中.在 ...
- poj1087&&hdu1526 最大流
多源多汇. 比较明显的建图.对于电器,可以从源点与各个电器相连,容量为1,表示这个电器有1个,然后对于各种接头,那可以各个接头与汇点相连,容量为1,表示每个接头只能用一次. 然后对于能够相互转换的接头 ...
- hdu4324 dfs
scanf("%1d")这种好像很慢. #include<stdio.h> #include<string.h> #define maxn 2010 str ...