• 洛谷P5280 [ZJOI2019]线段树


     

    https://www.luogu.org/problemnew/show/P5280

    省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不清楚(事实证明出来后再给我2个小时也还是没理清楚,只能说自己naive),而且也码不完,打了个20分暴力

    参考资料:题解

    首先,可以分开考虑各个点

    对于每个点,考虑对于t次修改,每一次标记为启用或不启用(共有$2^t$种标记方案),其中有多少种标记方案使得这个点最后有tag

    询问的答案就是每个点的答案之和

    对于每个点:

    f[i]表示i点自身有tag的方案数

    g[i]表示i或其祖先有tag的方案数(状态里必须是i或其祖先,如果只是祖先(或者只是父亲)就没法做了,以前卡在这个坑里了...)

    设这一次是第k次修改

    考虑根到某个节点u的链a1,a2,a3,..,at,u

    可以发现,这次修改对这个节点的影响分5类:(具体可以参考上面的“参考资料”)

    如果"把a1,a2,..,at之一节点直接打tag"(对应参考资料里第4类),则f[u]*=2,g[u]+=$2^{k-1}$

    如果"把u直接打tag"(对应第2类),则f[u]+=$2^{k-1}$,g[u]+=$2^{k-1}$

    如果"删掉a1,a2,..,at,u的全部tag"(对应第1类),则(啥也没)

    如果"删掉a1,a2,..,at的全部tag,如果删掉了至少1个tag就让u加上tag"(对应第3类),则f[u]+=g[u],g[u]*=2

    如果"删掉a1,a2,..,ap(p<t)的全部tag(如果删掉了至少1个tag就让a[p+1]加上tag)"(对应第5类),则f[u]*=2,g[u]*=2

    这一堆东西是可以用线段树直接维护的,其中第1,2,3类的直接暴力修改,4,5类用懒标记

    可以把方案数转换为概率,相当于每次做以上修改时加上的常数都要除以$2^{k-1}$,做完以上修改后再将所有点f和g都除以2,这样可以少记标记,减小常数

    这样的话,第4类就是g[u]=g[u]/2+1/2,第5类就是啥也没,剩下几类不需要lazytag比较容易,因此可以只记g的加法和乘法tag

    剩下几类:第1类f[u]/=2,g[u]/=2,第2类f[u]=(f[u]+1)/2,g[u]=(g[u]+1)/2,第3类f[u]=(f[u]+g[u])/2

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<vector>
      5 using namespace std;
      6 #define fi first
      7 #define se second
      8 #define mp make_pair
      9 #define pb push_back
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 const int md=998244353;
     13 #define addto(a,b) ((a)+=(b),((a)>=md)&&((a)-=md))
     14 #define multo(a,b) ((a)=ull(a)*(b)%md)
     15 namespace S
     16 {
     17     struct Nd
     18     {
     19         int f,g,addg,mulg;
     20         int sumf;
     21     }d[400011];
     22 #define LC (u<<1)
     23 #define RC (u<<1|1)
     24     inline void upd(int l,int r,int u)
     25     {
     26         d[u].sumf=d[u].f;
     27         if(l==r)    return;
     28         addto(d[u].sumf,d[LC].sumf);
     29         addto(d[u].sumf,d[RC].sumf);
     30     }
     31     inline void doAddg(int u,int x)
     32     {
     33         addto(d[u].g,x);
     34         addto(d[u].addg,x);
     35     }
     36     inline void doMulg(int u,int x)
     37     {
     38         multo(d[u].g,x);
     39         multo(d[u].addg,x);
     40         multo(d[u].mulg,x);
     41     }
     42     inline void pd(int l,int r,int u)
     43     {
     44         if(l==r)    return;
     45         if(d[u].mulg!=1)
     46         {
     47             doMulg(LC,d[u].mulg);
     48             doMulg(RC,d[u].mulg);
     49             d[u].mulg=1;
     50         }
     51         if(d[u].addg)
     52         {
     53             doAddg(LC,d[u].addg);
     54             doAddg(RC,d[u].addg);
     55             d[u].addg=0;
     56         }
     57     }
     58     void build(int l,int r,int u)
     59     {
     60         if(l==r)
     61         {
     62             d[u].mulg=1;
     63             return;
     64         }
     65         int mid=(l+r)>>1;
     66         build(l,mid,LC);build(mid+1,r,RC);
     67         d[u].mulg=1;
     68     }
     69     void setx(int L,int R,int l,int r,int u)//X=2^{k-2}
     70     {
     71         pd(l,r,u);
     72         if(L<=l && r<=R)
     73         {
     74             //4类,u的任意后代节点
     75             multo(d[u].addg,499122177);
     76             multo(d[u].mulg,499122177);
     77             addto(d[u].addg,499122177);
     78             //2类,u自身
     79             d[u].f=ull(d[u].f+1)*499122177%md;
     80             d[u].g=ull(d[u].g+1)*499122177%md;
     81             upd(l,r,u);
     82             return;
     83         }
     84         int mid=(l+r)>>1;
     85         if(L<=mid && mid<R)
     86         {
     87             setx(L,R,l,mid,LC);
     88             setx(L,R,mid+1,r,RC);
     89         }
     90         else if(L<=mid)
     91         {
     92             setx(L,R,l,mid,LC);
     93             //3类,RC
     94             pd(mid+1,r,RC);
     95             d[RC].f=ull(d[RC].f+d[RC].g)*499122177%md;
     96             upd(mid+1,r,RC);
     97             //5类,RC的任意后代节点(啥也不干)
     98         }
     99         else if(mid<R)
    100         {
    101             setx(L,R,mid+1,r,RC);
    102             //3类,LC
    103             pd(l,mid,LC);
    104             d[LC].f=ull(d[LC].f+d[LC].g)*499122177%md;
    105             upd(l,mid,LC);
    106             //5类,LC的任意后代节点(啥也不干)
    107         }
    108         //1类,u自身
    109         multo(d[u].f,499122177);
    110         multo(d[u].g,499122177);
    111         upd(l,r,u);
    112     }
    113 }
    114 int pw2[200011];//pw2[i]=2^{i-2}
    115 int n,m,mm;
    116 int main()
    117 {
    118     int i,idx,l,r;
    119     pw2[1]=499122177;
    120     for(i=2;i<=200000;++i)
    121         pw2[i]=ull(pw2[i-1])*2%md;
    122     scanf("%d%d",&n,&m);
    123     S::build(1,n,1);
    124     while(m--)
    125     {
    126         scanf("%d",&idx);
    127         if(idx==1)
    128         {
    129             scanf("%d%d",&l,&r);
    130             ++mm;
    131             S::setx(l,r,1,n,1);
    132         }
    133         else
    134         {
    135             printf("%llu
    ",ull(S::d[1].sumf)*pw2[mm+2]%md);
    136         }
    137     }
    138     return 0;
    139 }
    View Code
  • 相关阅读:
    随机生成一份试卷,试卷的种类分为单选、多选、判断三种题型。nodejs6.0 mysql
    git 常用命令
    ECMAScript 继承机制实现
    javascript正则表达式
    利用javascript实现二维数组的筛选
    iframe引入百度地图显示企业位置
    前端开发APP,从HBuilder开始~
    js闭包理解
    Python多线程threading与多线程中join()的用法
    Python中的装饰器
  • 原文地址:https://www.cnblogs.com/hehe54321/p/10643988.html
Copyright © 2020-2023  润新知