[Zjoi2017]bzoj4785 树状数组

这是一道神题。

结论题。

考场上我居然只打了暴搜,连dp都没敲。

省选debuff挺高的啊其实是因为我是蒟蒻智商不够

这题是非常可做的。

考完订正时,借着题解推了推,很快——

当询问的l>1时,是问l-1~r-1与l~r的答案是否一样。

当l==1时,是询问到点r的前缀和是否等于后缀和。

无脑树套树啊。

我的常数丑了uoj上额外数据T了,97分;bzoj上约19.5s过了。

Code:


/**************************************************************
    Problem: 4785
    User: chenyanbo
    Language: C++
    Result: Accepted
    Time:19572 ms
    Memory:354452 kb
****************************************************************/
 
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
using namespace std;
const int MO=998244353;
inline int read()
{
    int ret=0; char c=getchar();
    while(c>57 || c<48)c=getchar();
    while(c<=57 && c>=48)ret=ret*10+c-48,c=getchar();
    return ret;
}
struct Tree 
{
    int Son[2];
    int Val;
}T[300*N];
  
int Root[4*N];
int n,m,Cnt;
int ret;
  
inline int Power(int x, int k)
{
    int s=1;
    while(k)
    {
        if(k&1)s=(long long)s*x%MO;
        x=(long long)x*x%MO;
        k/=2;
    }
    return s;
}
  
inline int Merge(int p1, int p2)
{
    return ((long long)p1*p2+(long long)(1-p1+MO)*(1-p2+MO))%MO;
}
  
inline int NewNode()
{
    ++Cnt;
    T[Cnt].Son[0]=T[Cnt].Son[1]=0;
    T[Cnt].Val=1;
    return Cnt;
}
  
void Modify2(int &v, int l, int r, int x, int y, int mul) 
{
    if(!v)v=NewNode();
    if(l==x&&r==y) 
    {
        T[v].Val=Merge(T[v].Val,mul);
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid)Modify2(T[v].Son[0],l,mid,x,y,mul);
    else if(x>mid)Modify2(T[v].Son[1],mid+1,r,x,y,mul);
    else
    {
        Modify2(T[v].Son[0],l,mid,x,mid,mul);
        Modify2(T[v].Son[1],mid+1,r,mid+1,y,mul);
    }
}
  
void Modify1(int v, int l, int r, int x1, int y1, int x2, int y2, int val)
{
    if(l==x1&&r==y1)
    {
        Modify2(Root[v],0,n+1,x2,y2,val);
        return;
    }
    int mid=(l+r)>>1;
    if (y1<=mid)Modify1(v<<1,l,mid,x1,y1,x2,y2,val);
    else if(x1>mid)Modify1((v<<1)+1,mid+1,r,x1,y1,x2,y2,val);
    else
    {
        Modify1(v<<1,l,mid,x1,mid,x2,y2,val);
        Modify1((v<<1)+1,mid+1,r,mid+1,y1,x2,y2,val);
    }
}
  
void Search2(int v, int l, int r, int x)
{
    if(!v)return;
    ret=Merge(ret,T[v].Val);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)Search2(T[v].Son[0],l,mid,x);
    else Search2(T[v].Son[1],mid+1,r,x);
}
  
void Search1(int v, int l, int r, int x, int y)
{
    if(Root[v])Search2(Root[v],0,n+1,y);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)Search1(v<<1,l,mid,x,y);
    else Search1((v<<1)+1,mid+1,r,x,y);
}
  
int main() 
{
    n=read(),m=read();
    for(int i=1; i<=m ; ++i)
    {
        int op,l,r;
        op=read(),l=read(),r=read();
        if (op==1)
        {
            int p=Power(r-l+1,MO-2);
            if (l>1)Modify1(1,0,n,1,l-1,l,r,(1-p+MO)%MO);
            if (r<n)Modify1(1,0,n,l,r,r+1,n,(1-p+MO)%MO);
            p=(long long)2*p%MO;
            Modify1(1,0,n,l,r,l,r,(1-p+MO)%MO);
            Modify1(1,0,n,0,0,0,l-1,0);
            Modify1(1,0,n,0,0,r+1,n+1,0);
            Modify1(1,0,n,0,0,l,r,Power(r-l+1,MO-2)%MO);
        }
        else
        {
            ret=1;
            Search1(1,0,n,l-1,r);
            printf("%d\n",ret);
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值