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分治的更多相关文章

  1. 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)

    题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...

  2. 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 ...

  3. 2019南昌网络赛-I(单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上 ...

  4. ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

    ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...

  5. 2019南昌网络赛  I. Yukino With Subinterval 树状数组套线段树

    I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...

  6. ACM-ICPC 2019南昌网络赛F题 Megumi With String

    ACM-ICPC 南昌网络赛F题 Megumi With String 题目描述 给一个长度为\(l\)的字符串\(S\),和关于\(x\)的\(k\)次多项式\(G[x]\).当一个字符串\(str ...

  7. 2019南昌网络赛 hello 2019

    这道题和一道2017,2016的类似. A string t is called nice if a string “2017” occurs in t as a subsequence but a ...

  8. 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)} ...

  9. 2019南昌网络赛-M(二分)

    题目链接:https://nanti.jisuanke.com/t/38232 题意:给定字符串s(长度<=1e5),然后N组样例(N<=1e5),每组输入一个字符串t判断t是否为s的字串 ...

随机推荐

  1. POJ 2031 Building a Space Station (prim裸题)

    Description You are a member of the space station engineering team, and are assigned a task in the c ...

  2. 【CodeVS】1083 Cantor表

    1083 Cantor表 1999年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 现代数学的著名证明之 ...

  3. 安装tengine及淘宝会话保持模块

    安装tengine及淘宝会话保持模块 下载http://tengine.taobao.org/ 解压tar -zxvf tengine-2.3.0.tar.gz 安装GCC: yum -y insta ...

  4. WCF 服务

    1.代码 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Seriali ...

  5. System.ArgumentException: 回发或回调参数无效。在配置中使用 < pages enableEventValidation="true"/>

    转载自http://blog.csdn.net/dongge825/article/details/7868151 关于在同一个页面中使用Gridview控件的时候发现气updaeting事件无法被服 ...

  6. pygame-常用的方法

    1.pygame常用的方法 2.语音 图片

  7. PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品,产品设计严格遵循国际数据挖掘标准CRISP-DM(跨行业数据挖掘过程标准),具备完备的数据准备、模型构建、模型评估、模型管理、海量数据处理和高纬数据可视化分析能力。

    http://www.meritdata.com.cn/article/90 PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品, ...

  8. 编程语言分类及python所属类型

    编程语言分类及python所属类型 编程语言主要从以下几个角度为进行分类:编译型和解释型.静态语言和动态语言.强类型定义语言和弱类型定义语言. 编译和解释的区别是什么? 编译器是把源程序的每一条语句都 ...

  9. 【JZOJ3886】【长郡NOIP2014模拟10.22】道路维护

    CCC 最近徆多人投诉说C国的道路破损程度太大,以至亍无法通行 C国的政府徆重视这件事,但是最近财政有点紧,丌可能将所有的道路都进行维护,所以他们决定按照下述方案进行维护 将C国抽象成一个无向图,定义 ...

  10. 【Django入坑之路】Django后台上传图片,以及前端的显示

    #setting配置: MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media") # ...