I. Yukino With Subinterval 树套树入门题

I. Yukino With Subinterval
题意:有两种操作,第一种修改一个位置的值,第二种求给定区间[l,r]内有多少合法区间。合法区间定义:al = al+1 = … = ar ,且该区间为最长。
题解:如果这题不带修改,主席树就写完了。那么带修改动态开点线段树套树状数组。
注意:这题卡常,需要快读。

#include<bits/stdc++.h>
#define m (l+r)/2
#define low(x) x&-x
using namespace std;
const int maxn = 2e5+10;
int n,q;
int cnt,cnz,V[22];
int rt[maxn],a[maxn],sum[maxn*210],ls[maxn*210],rs[maxn*210];
void up(int l,int r,int k,int v)
{
    for(int i=1;i<=cnz;i++)
    sum[V[i]] += v;
    if(l==r) return ;
    if(k>m){
       for(int i=1;i<=cnz;i++){
        if(!rs[V[i]]) rs[V[i]] = ++cnt;
        V[i] = rs[V[i]];
       }
       up(m+1,r,k,v);
    }
    else {
       for(int i=1;i<=cnz;i++)
       {
           if(!ls[V[i]]) ls[V[i]] = ++cnt;
           V[i] = ls[V[i]];
       }
       up(l,m,k,v);
    }
}
int qu(int l,int r,int ql,int qr)
{
    if(ql<=l&&qr>=r)
    {
    int ans  = 0;
     for(int i=1;i<=cnz;i++)
     ans += sum[V[i]];
     return ans;
    }
    int ans = 0,V2[22];
    if(ql<=m)
    {
     for(int i=1;i<=cnz;i++)
     V2[i] = V[i] , V[i] = ls[V[i]];
     ans += qu(l,m,ql,qr);
     for(int i=1;i<=cnz;i++)
        V[i] = V2[i];
    }
    if(qr>m)
    {
      for(int i=1;i<=cnz;i++)
        V[i] = rs[V[i]];
      ans += qu(m+1,r,ql,qr);
    }
    return ans ;
}
void modify(int x,int k,int v)
{
    cnz = 0;
    for(;x<=n;x+=low(x))
    V[++cnz] = rt[x];
    up(1,n,k,v);
}
int query(int x,int ql,int qr)
{
    cnz = 0;
    for(;x>0;x-=low(x))
    V[++cnz] = rt[x];
    return qu(1,n,ql,qr);
}
#define reads(n) FastIO::read(n)
namespace FastIO {
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }
    bool read(int& x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }
};
int main()
{
    FastIO::read(n);FastIO::read(q);
   for(int i=1;i<=n;i++)
    rt[i] = ++cnt;
   for(int i=1;i<=n;i++)
   {
       reads(a[i]);
   //    scanf("%d",&a[i]);
       if(a[i]!=a[i-1])
       modify(i,a[i],1);
   }
   int op,l,r,x,y;
   for(int i=1;i<=q;i++)
   {
      reads(op);
   //  scanf("%d",&op);
    if(op==1)
    {
     reads(l);reads(r);
  //   scanf("%d%d",&l,&r);
     if(a[l]==r) continue;
     if(a[l-1]!=a[l]) {
            modify(l,a[l],-1);
          if(r!=a[l-1]) modify(l,r,1);
     }
     if(a[l-1]==a[l]){
            modify(l,r,1);
     }
     if(a[l]==a[l+1]){
            modify(l+1,a[l+1],1);
     }
     else if(a[l+1]==r){
            modify(l+1,a[l+1],-1);
     }
     a[l] = r;
    }
    else {
     reads(l);reads(r);reads(x);reads(y);
 //      scanf("%d%d%d%d",&l,&r,&x,&y);
     int ans = query(rt[r],x,y) - query(rt[l-1],x,y);
      if(a[l]==a[l-1]&&a[l]>=x&&a[l]<=y) ans ++;
      printf("%d\n",ans);
    }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值