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. mysql 分表-横向,纵向

    mysql 分库分表 分表是分散数据库压力的好方法. 分表,最直白的意思,就是将一个表结构分为多个表,然后,可以再同一个库里,也可以放到不同的库. 当然,首先要知道什么情况下,才需要分表.个人觉得单表 ...

  2. php数字转人民币金额大写

    numToRmb.php <?php header("content-type:text/html;charset=utf-8"); function numToRmb($n ...

  3. 计蒜客 Zoning Houses(线段树区间最大次大)

    Given a registry of all houses in your state or province, you would like to know the minimum size of ...

  4. 【BZOJ2809】【APIO2012】dispatching

    左偏树. 每个子节点维护大根堆,遍历一个儿子就往自己合并,合并发现钱不够了就删除队顶. //Achen #include<algorithm> #include<iostream&g ...

  5. mac 下的 homebrew

    如果安装了macport 就不能安装homebrew ,必须先卸载macport $ sudo port -f uninstall installed$ sudo rm -rf \/opt/local ...

  6. ASP.NET CORE使用MailKit的一个故障点分析

    ASP.NET CORE下有需要发邮件的需求,但是原来framework下的 system.net.mail,没有实现smtpclient的功能(当时看是没有,说是准备并入.net core来着),所 ...

  7. Redhad的开源Paas平台:OpenShift

    参考redHat的官方文章翻译而来:https://openshift.redhat.com/community/wiki/architecture-overview OpenShift Origin ...

  8. Linux操作系统各版本ISO镜像下载(包括oracle linux\redhat\centos\u

    Linux操作系统各版本ISO镜像下载(包括oracle linux\redhat\centos\ubuntu\debian等) 1.Oracle Linux(下载地址) (1)OracleLinux ...

  9. 【水滴石穿】react-native-book

    先推荐一个学习的地址:https://ke.qq.com/webcourse/index.html#cid=203313&term_id=100240778&taid=12778558 ...

  10. 移动端以及 PC浏览器页面分享到朋友圈等的功能实现

    我们经常可以在一些 app上看到分享到朋友圈.微信好友.qq好友等功能,例如 饿了么.美团等 app,下单之后就会弹出给好友发红包的 modal窗,这在 app上很常见,app的权限可以很大,甚至连启 ...