zoukankan      html  css  js  c++  java
  • [JZOJ] 5837.Omeed

    先摆出来这个式子

    [score=Asum S_i+Bsum S_i imes f(i) ]

    先研究(f)函数(也就是Combo函数)

    显然的有

    [f(i)=P_i(f(i-1)+1)+t(1-P_i)f(i-1) ]

    化简得

    [f(i)=(P_i+t-tP_i)f(i-1)+P_i ]

    再考虑一下期望意义下的式子

    [score=Asum P_i+Bsum P_i imes f(i) ]

    然而,这是不对的,第一个样例都过不了

    问题出在哪?就在(P_i imes f(i))这里

    (P_i)意味着第i位必为1,此时的(f(i))应当在(2)式中将(P_i)代为1,也就是此时

    [score=Asum P+Bsum P_i imes(f(i-1)+1) ]

    到这里,第一部分就是一个区间和,第二部分考场上直接写暴力了

    现在考虑一下如何快速维护第二个信息

    [cost(i,j)=sumlimits_{k=i}^jP_k imes (f(k-1)+1)=sumlimits_{k=i}^jP_kf(k-1)+P_k ]

    和式里面是一个一次函数的形式,自变量是(f(x)),根据(3)式,(f(x))也是一个一次函数的形式

    这就可以用线段树维护了,单点修改很好实现,考虑(P_i+d)(d)的贡献即可

    对于一个区间([L,R]),记录(k_1,b_1,k_2,b_2)表示(f(R)=k_1f(L-1)+b_1,cost(L,R)=k_2f(L-1)+b_2)

    由于它们都是一次函数,所以一定可以这样表出

    现在考虑如何合并区间信息,考虑边界情况,对于一个区间([i,i]),根据(3)和(6)有

    (k_1=P_i+t-tP_i , b1=P_i, k_2=P_i, b_2=P_i)

    考虑一个区间([L,R]),中点为(m)

    [egin{align*} f(m)&=k_1f(L-1)+b_1\ f(R)&=k_1'f(m)+b_1'\ herefore f(R)&=k_1k_1'f(L-1)+k_1'b_1+b_2\ cost(L,m)&=k_2f(L-1)+b_2\ cost(m+1,R)&=k_2'f(m)+b_2'\ herefore cost(L,R)&=(k_2+k_2'k_1)f(L-1)+b_2+b_2'+k_2'b_1 end{align*} ]

    这样就能合并区间了,由于(f(L-1)=0),所以答案区间([L,R])的答案就是

    [score[L,R]=Asum_{i=L}^RP_i+B imes b_2 ]

    只维护(f)是不能做的,考场上并没有想到再维护一个(cost),参考了杨神犇的博客
    线段树真是处理区间可合并信息的利器

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    inline char gc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=gc(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=gc();
      return ret*f;
    }
    #define space() putchar(' ')
    #define nextline() putchar('
    ')
    void pot(int x){if(!x)return;pot(x/10);putchar('0'+x%10);}
    void out(int x){if(!x)putchar('0');if(x<0)putchar('-'),x=-x;pot(x);}
    
    const int MAXN = 500005;
    const int MOD = 998244353;
    
    int mul(int x,int y){return (1ll*x*y)%MOD;}
    void Mul(int &x,int y){x=mul(x,y);}
    int sub(int x,int y){return x-y<0?x-y+MOD:x-y;}
    int add(int x,int y){if(y>=0)return x+y>MOD?x+y-MOD:x+y;else return sub(x,-y);}
    void Add(int &x,int y){x=add(x,y);}
    
    inline int qpow(int x,int y){
      int ret=1;
      while(y){
        if(y&1)Mul(ret,x);
        Mul(x,x);
        y>>=1;
      }
      return ret;
    }
    inline int inv(int x){return qpow(x,MOD-2);}
    
    int n,q,t,dt,ta,tb,A,B;
    int p[MAXN];
    
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    struct Node{
      int k1,k2,b1,b2;
      Node(int x=1,int y=0,int u=1,int v=0){k1=x;b1=y;k2=u;b2=v;}
    }node[MAXN<<2];
    inline Node merge(const Node &x,const Node &y){
      return Node(
        mul(x.k1,y.k1),
        add(mul(x.b1,y.k1),y.b1),
        add(x.k2,mul(y.k2,x.k1)),
        add(mul(y.k2,x.b1),add(x.b2,y.b2))
      );
    }
    void build(int L,int R,int cur,int l,int r){
      if(l==r){
        node[cur]=Node(sub(add(p[l],t),mul(t,p[l])),p[l],p[l],p[l]);
        return;
      }
      if(L<=mid)build(L,R,ls,l,mid);
      if(mid <R)build(L,R,rs,mid+1,r);
      node[cur]=merge(node[ls],node[rs]);
    }
    void update(int pos,int cur,int l,int r,int w){//add w
      if(l==r){
        Add(node[cur].k1,mul(dt,w));
        Add(node[cur].b1,w);
        Add(node[cur].k2,w);
        Add(node[cur].b2,w);
        return;
      }
      if(pos<=mid) update(pos,ls,l,mid,w);
      else update(pos,rs,mid+1,r,w);
      node[cur]=merge(node[ls],node[rs]);
    }
    Node query(int L,int R,int cur,int l,int r){
      if(L<=l&&r<=R) return node[cur];
      if(L<=mid&&(!(mid<R)))return query(L,R,ls,l,mid);
      if((!(L<=mid))&&(mid<R))return query(L,R,rs,mid+1,r);
      return merge(query(L,R,ls,l,mid),query(L,R,rs,mid+1,r));
    }
    struct BIT{
      int b[MAXN];
      void update(int x,int w){
        for(int i=x;i<=n;i+=i&-i)Add(b[i],w);
      }
      int query(int x){
        int ret=0;
        for(int i=x;i;i-=i&-i)Add(ret,b[i]);
        return ret;
      }
    }bit;
    
    void answer(){
      int l,r;
      l=rd();r=rd();
      int ans=0;
      Add(ans,mul(A,add(bit.query(r),-bit.query(l-1))));
      Add(ans,mul(B,query(l,r,1,1,n).b2));
      out(ans);nextline();
    }
    void change(){
      int pos,wa,wb,w;
      pos=rd();wa=rd();wb=rd();
      w=mul(wa,inv(wb));
      bit.update(pos,-p[pos]);
      bit.update(pos,w);
      update(pos,1,1,n,-p[pos]);
      update(pos,1,1,n,w);
      p[pos]=w;
    }
    int main(){
      freopen("omeed.in","r",stdin);
      freopen("omeed.out","w",stdout);
      rd();
      n=rd();q=rd();ta=rd();tb=rd();A=rd();B=rd();
      t=mul(ta,inv(tb));
      dt=add(1,-t);
      int x,y;
      for(int i=1;i<=n;i++){
        x=rd();y=rd();
        p[i]=mul(x,inv(y));
        bit.update(i,p[i]);
      }
      build(1,n,1,1,n);
      for(int i=1;i<=q;i++){
        x=rd();
        if(x==1) answer();
        else change();
      }
    }
    
  • 相关阅读:
    JavaScript常见注意点(一)
    jspServlet2.5和Servlet3的区别
    jspMVC案例
    jQuery入口函数的写法
    Servlet 简介
    jspMVC设计模式和Servlet2.5入门案例
    display 属性
    JSON简单使用
    Tomcat修改端口号
    php开发环境简单配置
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9817260.html
Copyright © 2011-2022 走看看