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

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+6;
struct node{
   int l,r;
   int cnt;
}tree[maxx*220];
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)>>1;
   if (pos<=mid){
    inserts(tree[now].l,l,mid,pos,w);
   }else{
    inserts(tree[now].r,mid+1,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],1,n,a[x],w);
   }
}
int query(int l,int r,int ql,int qr){
    if (r<ql || l>qr){
        return 0;
    }
    int tmpl[1000],tmpr[1000];
    int s=0,mid=(l+r)>>1,sum=0;
    for(int i=1;i<=cnt1;i++)s-=tree[trl[i]].cnt,tmpl[i]=trl[i];
    for(int i=1;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=1;i<=cnt1;i++){
            trl[i]=tree[tmpl[i]].l;
        }
        for (int i=1;i<=cnt2;i++){
            trr[i]=tree[tmpr[i]].l;
        }
        sum+=query(l,mid,ql,qr);
    }
    if (mid<qr){
        for (int i=1;i<=cnt1;i++){
            trl[i]=tree[tmpl[i]].r;
        }
        for (int i=1;i<=cnt2;i++){
            trr[i]=tree[tmpr[i]].r;
        }
        sum+=query(mid+1,r,ql,qr);
    }
    return sum;
}
int main(){
  int m;
  scanf("%d%d",&n,&m);
    cnt=cnt1=cnt2=0;
  for (int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    if (a[i]!=a[i-1])add(i,1);
  }
  int op;
  int pos,v,l,r,x,y;
  while(m--){
    scanf("%d",&op);
    if(op==1){
        scanf("%d%d",&pos,&v);
        if (a[pos]==v)continue;
        if(a[pos]!=a[pos-1]){
            add(pos,-1);
        }
        if(a[pos]==a[pos+1]){
            add(pos+1,1);
        }else if (a[pos+1]==v){
            add(pos+1,-1);
        }
        a[pos]=v;
        if (a[pos]!=a[pos-1]){
            add(pos,1);
        }
    }else {
        scanf("%d%d%d%d",&l,&r,&x,&y);
        cnt1=cnt2=0;
        int f=0;
        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(1,n,x,y)+f);
    }
  }
  return 0;
}

原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11516694.html

时间: 2024-10-03 10:32:06

2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组的相关文章

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

题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上弄了3小时,思路大体都是对的,但就是没法实现.这几天恶补线段树. 首先可以利用单调栈来查找满足a[i]为最小值的最大区间L[i]~R[i].然后利用线段树求一个段的和sum.最小前缀lsum和最小后缀rsum.然后遍历a[i]: a[i]>0:最优为sum(L[i],R[i])*a[i] a[i]<

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

ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询问子区间中某个值域的数的个数,连续的相同数字只记为一个.(即统计数字段的个数) 2 L R x y 数据范围: 1 ≤ n,m ≤ 2×10^5 1 ≤ a[i] ≤ n 解题思路: 连续重复的数字只记一次.所以考虑将每个数字段除第一个出现外的数字都删去(记为0).在读入操作的时候暴力模拟,同时维护

2019徐州网络赛 XKC&#39;s basketball team 线段树

网址:https://nanti.jisuanke.com/t/41387 题意: 大家好,我是训练时长两年半的个人练习生蔡徐坤,我的爱好是唱,跳,rap,篮球. 给出一段长度为$n,(n \leq 1e5)$的序列,对每一个数,求出它和它后面比它大$m$的数中间夹着的数的数量,没有输出$-1$. 题解: 直接建线段树,维护最大值,然后查询时对第$i$个数,搜索区间$[i,n]$之中大于$num[i]+m$的值的位置的最大值,具体操作是先限定区间,然后求出所有合法位置,取最大值,如果搜索不到则返

2019 南昌网络赛icpc I题 cdq分治或分块

题意:给你一个数组,然后每次有两种操作,操作一是修改数组里的数,操作二是查询区间[ l , r ] 里有多少个子区间满足以下条件:1.子区间内的数全部相同.2.子区间内的数在x到y之间.3.子区间得是不能延伸的. 题目链接:https://nanti.jisuanke.com/t/41356 题解:首先转化问题,设 b[ i ] = a[i]==a[i-1] ? 0 : a[i],然后问题就变成了问询区间内有多少个x到y之间的数.(注意左端点特判)这不就是主席树....带修改...好,树状数组加

2019 ICPC 南昌网络赛

2019 ICPC 南昌网络赛 比赛时间:2019.9.8 比赛链接:The 2019 Asia Nanchang First Round Online Programming Contest 总结 // 史上排名最高一次,开场不到两小时队友各A一题加水题共四题,排名瞬间升至三四十名 // 然后后三小时就自闭了,一题都没有突破...最后排名211 hhhh ? ? B. Fire-Fighting Hero 题意 队友做的,待补. ? AC代码 #include<cstdio> #includ

2019 CCPC网络赛

一到网络赛,大家都是东亚之光 1001 00:23:46 solved by hl 签到 枚举一下位就行了 #include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset

query 2019徐州网络赛(树状数组)

query \[ Time Limit: 2000 ms \quad Memory Limit: 262144 kB \] 题意 补题才发现比赛的时候读了一个假题意.... 给出长度为 \(n\) 的排列,在给出 \(m\) 次询问,每次询问有一对 \(l.r\),问满足 \(min(ai, aj) = gcd(ai, aj)\) 的 \(pair(i, j)\) 对数. 思路 考虑离线做 先把每个数出现的位置记录下来,然后预处理出所有的 \(pair\). 对于一个数字 \(x\),其满足条件

2019年ICPC南昌网络赛 J. Distance on the tree 树链剖分+主席树

边权转点权,每次遍历到下一个点,把走个这条边的权值加入主席树中即可. #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> using namespace std; const int maxx = 2e5+10; struct node{ int l,r,cnt; }tree[maxx*40]; int head[maxx],rk[maxx],siz[maxx

2019 上半年 南昌网络赛

B.Fire-Fighting Hero 图论题-单源最短路径:添加一个顶点,连接各个救火团队所在的救火点,路径长度均设为 0,设该顶点为源,即变成了单源最短路径问题.使用两次Dijkstra算法可求出两个最短路径 的最大值.比较时将救火团队的乘以C进行比较可避免分数操作. #include<iostream> #include<string.h> #include<algorithm> #include<math.h> #define INF 0x3f3f