[我可能是个ZZ啊] UOJ #291 【ZJOI2017】树状数组

再次怀疑自己的智商
这个东西 不难发现求成了后缀和
l>1 时就是询问 al1=ar 的概率
l=1 特判下
然后就是一个修改会对几个矩阵范围内的询问点造成影响
具体就是两个概率 p q 变成 p(1q)+q(1p)
然后这个东西 分治啊 树套树啊 都行吧
我懒就随手打了个KDTREE 竟然跑过了
rank倒数第二 竟然没有垫底

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int P=998244353;
const int N=100005;

ll inv[N];

inline void Pre(int n){
  inv[1]=1; for (int i=2;i<=n;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;
}

int n,m;
int z[N],x[N],y[N];

inline ll mul(ll p,ll q){
  return (p*(1+P-q)+q*(1+P-p))%P;
}

namespace SEG{
  ll T[N<<2];
  inline void Build(int x,int l,int r){
    T[x]=0; int mid=(l+r)>>1;
    if (l==r) return;
    Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
  }
  int ql,qr; ll t;
  inline void modify(int x,int l,int r){
    if (ql<=l && r<=qr){
      T[x]=mul(t,T[x]); return;
    }
    if (T[x]) T[x<<1]=mul(T[x],T[x<<1]),T[x<<1|1]=mul(T[x],T[x<<1|1]),T[x]=0;
    int mid=(l+r)>>1;
    if (ql<=mid) modify(x<<1,l,mid);
    if (qr>mid) modify(x<<1|1,mid+1,r);
  }
  inline void Modify(int _l,int _r,ll _t){
    ql=_l; qr=_r; t=_t;
    modify(1,1,n);
  }
  inline ll Query(int x,int l,int r,int t){
    if (l==r) return T[x];
    if (T[x]) T[x<<1]=mul(T[x],T[x<<1]),T[x<<1|1]=mul(T[x],T[x<<1|1]),T[x]=0;
    int mid=(l+r)>>1;
    if (t<=mid) return Query(x<<1,l,mid,t);
    else return Query(x<<1|1,mid+1,r,t);
  }
}

namespace KD{
  int D;
  int x1,x2,y1,y2; ll t;
  struct PP{
    int ls,rs; ll T,F;
    int x[2],minv[2],maxv[2];
    PP() {}
    PP(int _x,int _y){ x[0]=_x; x[1]=_y; }
    bool operator < (const PP &B) const{
      return x[D]==B.x[D]?x[D^1]<B.x[D^1]:x[D]<B.x[D];
    }
    bool inside(){
      return x1<=x[0] && x[0]<=x2 && y1<=x[1] && x[1]<=y2;
    }
    bool in(){
      return x1<=minv[0] && maxv[0]<=x2 && y1<=minv[1] && maxv[1]<=y2;
    }
    bool out(){
      return maxv[0]<x1 || minv[0]>x2 || maxv[1]<y1 || minv[1]>y2; 
    }
  }p[N];
  int tot,rt;
#define LS p[x].ls
#define RS p[x].rs
  inline void upd(int x){
    for (int i=0;i<2;i++){
      p[x].minv[i]=p[x].maxv[i]=p[x].x[i];
      if (LS) {
    p[x].minv[i]=min(p[x].minv[i],p[LS].minv[i]);
    p[x].maxv[i]=max(p[x].maxv[i],p[LS].maxv[i]);
      }
      if (RS) {
    p[x].minv[i]=min(p[x].minv[i],p[RS].minv[i]);
    p[x].maxv[i]=max(p[x].maxv[i],p[RS].maxv[i]);
      }
    }
  }
  inline void push(int x){
    if (p[x].F){
      if (LS) p[LS].F=mul(p[x].F,p[LS].F),p[LS].T=mul(p[x].F,p[LS].T);
      if (RS) p[RS].F=mul(p[x].F,p[RS].F),p[RS].T=mul(p[x].F,p[RS].T);
      p[x].F=0;
    }
  }
  inline void Build(int &x,int l,int r,int d){
    if (l>r){ x=0; return; }
    D=d; int mid=(l+r)>>1;
    nth_element(p+l,p+mid,p+r+1);
    x=mid; p[x].F=p[x].T=0;
    Build(p[mid].ls,l,mid-1,d^1);
    Build(p[mid].rs,mid+1,r,d^1);
    upd(mid);
  }
  inline void modify(int x){
    if (p[x].in()) { p[x].F=mul(t,p[x].F); p[x].T=mul(t,p[x].T); return; }
    if (p[x].out()) return;
    if (p[x].inside()) p[x].T=mul(t,p[x].T);
    push(x);
    if (LS) modify(LS);
    if (RS) modify(RS);
  }
  inline void Modify(int _x1,int _x2,int _y1,int _y2,ll _t){
    x1=_x1; x2=_x2; y1=_y1; y2=_y2; t=_t;
    modify(rt);
  }
  inline ll query(int x,int _x,int _y,int d){
    if (p[x].x[0]==_x && p[x].x[1]==_y)
      return p[x].T;
    push(x);
    D=d;
    if (PP(_x,_y)<p[x]) return query(LS,_x,_y,d^1);
    else return query(RS,_x,_y,d^1);
  }
  inline ll Query(int x,int y){
    return query(rt,x,y,0);
  }
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); Pre(n);
  for (int i=1;i<=m;i++){
    using namespace KD;
    read(z[i]); read(x[i]); read(y[i]);
    if (z[i]==2){
      x[i]--;
      if (!x[i]) z[i]++;
      if (z[i]==2) p[++tot].x[0]=x[i],p[tot].x[1]=y[i];
    }
  }
  SEG::Build(1,1,n);
  KD::Build(KD::rt,1,KD::tot,0);
  int sum=0;
  for (int i=1;i<=m;i++)
    if (z[i]==1){
      sum^=1; int l=x[i],r=y[i];
      SEG::Modify(l,r,inv[r-l+1]);
      if (l-1>=1) KD::Modify(1,l-1,l,r,inv[r-l+1]);
      if (r+1<=n) KD::Modify(l,r,r+1,n,inv[r-l+1]);
      KD::Modify(l,r,l,r,2*inv[r-l+1]%P);
    }else if (z[i]==2){
      ll t=KD::Query(x[i],y[i]);
      printf("%lld\n",(1+P-t)%P);
    }else{
      ll t=SEG::Query(1,1,n,y[i]);
      printf("%lld\n",!sum?(1+P-t)%P:t);
    }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值