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. java使用正则表达式,去除windows系统中文件名的非法路径

    w哦我爬取一个页面,并且把附件下载下来,保存,有的时候文件名,带*号,所以,无法保存 这时候就要删除所有的非法字符 String fileName = resourceName + fileTypt; ...

  2. solr问题missing content stream

    在使用solrj建立索引的时候,报错:missing content stream; 原因在于 HttpSolrServer httpSolrServer = new HttpSolrServer(s ...

  3. Django ORM中的查询,删除,更新操作

    ORM查询操作 修改views.py文件 from django.shortcuts import render, HttpResponse from app01 import models from ...

  4. 解释器模式(Interpreter、Context、Expression)

    (给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子.) 解释器模式的定义是一种按照规定语法进行解析的方案,在现在项目中使用的比较少,其定义如下: Given ...

  5. Hdu 4920矩阵乘法(内存访问的讲究)

    题目链接 Matrix multiplication Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K ( ...

  6. 【python小随笔】Django+错误日志(配置Django报错文件指定位置)

    1:  自定义日志文件.py----------几个文件需要创建日志,就需要重新定义几份 # 定义一个日志文件 创建一个操作日志对象logger file_1 = logging.FileHandle ...

  7. git命令入门

    http://www.cocoachina.com/ios/20160629/16855.html 译者序:这是一篇给像我这样的新手或者是熟悉图形工具的老鸟看的.仅作为快速入门的教程. git 现在的 ...

  8. 《2019上半年DDoS攻击态势报告》发布:应用层攻击形势依然严峻,海量移动设备成新一代肉鸡

    2019年上半年,阿里云安全团队平均每天帮助用户防御2500余次DDoS攻击,与2018年持平.目前阿里云承载着中国40%网站流量,为全球上百万客户提供基础安全防御.可以说,阿里云上的DDoS攻防态势 ...

  9. PHP学习(函数)

    可变函数,即通过变量的值来调用函数,因为变量的值是可变的,所以可以通过改变一个变量的值来实现调用不同的函数. 经常会用在回调函数.函数列表,或者根据动态参数来调用不同的函数.可变函数的调用方法为变量名 ...

  10. Codeforces 414A

    题目链接 首先考虑无解的情况: n / 2 > k 或者 n==1 且 k != 0 (因为两个数的最大公约数最小为1) 然后因为有 n / 2 组(把 a[i] 和 a[i+1] 看成一组), ...