洛谷P3688/uoj#291. [ZJOI2017]树状数组

传送门(uoj)

传送门(洛谷)

这里是题解以及我的卡常数历程

话说后面那几组数据莫不是lxl出的这么毒

首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间和。因为模\(2\)意义下的加法就是异或,所以错误查询和正确查询相等就意味着\(a[l-1]\)\(a[r]\)相等

我们不能简单的维护每个位置是什么值的概率,比方说一次修改了\([1,2]\),虽然这两个位置为\(1\)的概率都是\(\frac{1}{1}\),但它们的值绝对不相等

所以我们需要维护二元组\((x,y)\)代表\(x\)\(y\)相等的概率,需要开一个二维线段树(我到今天才知道原来二维线段树该这么写……以前一直都是一个父亲四个儿子……)

那么对于一次修改操作\((l,r)\),会发生改变的二元组有

1.左端点在\([1,l-1]\)之间,右端点在\([l,r]\)之间

2.左端点在\([l,r]\)之间,右端点在\([r+1,n]\)之间

3.左右端点都在\([l,r]\)之间

设区间长度为\(len\),那么对于\(1,2\),这次操作有\(\frac{1}{len}\)的概率使它们取反,对于\(3\)操作,这次操作有\(\frac{2}{len}\)的概率使它们取反

关于标记合并的问题的话,如果设两次取反的概率分别为\(p,q\),那么最终被取反的概率为\(p(1-q)+q(1-p)\)

然而我们需要特判\(l=1\)的情况,因为按题目中的树状数组的写法此时会返回\(0\),所以这个时候就是查询\([1,l-1]\)\([r+1,n]\)是否相等,我们可以单独开一个一维线段树,对每个位置\(i\)维护\([1,i-1]\)\([i+1,n]\)相等的概率,需要的时候在线段树上查询就是了

接下来是卡常问题

首先是标记永久化,即我们在线段树上打标记的时候不下传,而是直接叠在那一层,查询的时候把经过路径上的所有标记直接加到答案上去

其次,对于答案和询问的左右端点,我们不传参,直接开全局变量

再者,一维线段树上,在\(r-l+1\leq 7\)的时候我们不继续递归下去而是改成暴力打标记

最后,我们维护有序的二元组\((x,y)\)的时候令\(x<y\),所以在二维线段树上打标记的时候不用去管第二维里比第一维小的那部分

什么读优输优手打\(max\)之类的我就不多说了……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5,P=998244353,M=4e7+5;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
inline int calc(R int x,R int y){return (1ll*x*(P+1-y)%P+1ll*y*(P+1-x)%P)%P;}
inline int max(const R int &x,const R int &y){return x>y?x:y;}
inline int min(const R int &x,const R int &y){return x<y?x:y;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
int n,m,ans,op,l,r,len,inv[N],x,y;
struct tree1{
    int rt[N<<2],val[M],ls[M],rs[M],a[N],cnt;
    void ins(int &p,int l,int r,int ql,int qr,int v){
        if(!p)p=++cnt;
        if(ql<=l&&qr>=r)return val[p]=calc(val[p],v),void();
        int mid=(l+r)>>1;
        if(ql<=mid)ins(ls[p],l,mid,ql,qr,v);
        if(qr>mid)ins(rs[p],mid+1,r,ql,qr,v);
    }
    void query(int p,int l,int r){
        if(!p)return;ans=calc(ans,val[p]);
        if(l==r)return;int mid=(l+r)>>1;
        y<=mid?query(ls[p],l,mid):query(rs[p],mid+1,r);
    }
    void qins(int p,int l,int r,int ql,int qr,int dl,int dr,int v){
        if(ql<=l&&qr>=r)return ins(rt[p],1,n,max(dl,l),dr,v);
        int mid=(l+r)>>1;
        if(ql<=mid)qins(p<<1,l,mid,ql,qr,dl,dr,v);
        if(qr>mid)qins(p<<1|1,mid+1,r,ql,qr,dl,dr,v);
    }
    void qquery(int p,int l,int r){
        query(rt[p],1,n);
        if(l==r)return;int mid=(l+r)>>1;
        x<=mid?qquery(p<<1,l,mid):qquery(p<<1|1,mid+1,r);
    }
}T;
struct tree2{
    int val[N<<2],a[N];
    void update(int l,int r,int v){fp(i,l,r)a[i]=calc(a[i],v);}
    void ins(int p,int l,int r,int ql,int qr,int v){
        if(r-l+1<=7)return update(max(ql,l),min(qr,r),v);
        if(ql<=l&&qr>=r)return val[p]=calc(val[p],v),void();
        int mid=(l+r)>>1;
        if(ql<=mid)ins(p<<1,l,mid,ql,qr,v);
        if(qr>mid)ins(p<<1|1,mid+1,r,ql,qr,v);
    }
    void query(int p,int l,int r){
        if(r-l+1<=7)return ans=calc(ans,a[x]),void();
        ans=calc(ans,val[p]);
        if(l==r)return;int mid=(l+r)>>1;
        x<=mid?query(p<<1,l,mid):query(p<<1|1,mid+1,r);
    }
}G;
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),m=read();
    inv[0]=inv[1]=1;fp(i,2,n)inv[i]=1ll*inv[P%i]*(P-P/i)%P;
    while(m--){
        op=read(),l=read(),r=read();
        if(op==1){
            len=r-l+1;
            if(l>1)T.qins(1,1,n,1,l-1,l,r,inv[len]),G.ins(1,1,n,1,l-1,1);
            if(r<n)T.qins(1,1,n,l,r,r+1,n,inv[len]),G.ins(1,1,n,r+1,n,1);
            if(l!=r)T.qins(1,1,n,l,r,l,r,mul(2,inv[len])),G.ins(1,1,n,l,r,dec(1,inv[len]));
        }else{
            ans=1;
            if(l==1)x=r,G.query(1,1,n);
            else x=l-1,y=r,T.qquery(1,1,n);
            print(ans);
        }
    }return Ot(),0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10258591.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园2.0是高校信息化建设的新阶段,它面对着外部环境变化和内生动力的双重影响。国家战略要求和信息技术的快速发展,如云计算、大数据、物联网等,为智慧校园建设提供了机遇,同时也带来了挑战。智慧校园2.0强调以服务至上的办学理念,推动了教育模式的创新,并对传统人才培养模式产生了重大影响。 智慧校园建设的解决之道是构建一个开放、共享的信息化生态系统,利用互联网思维,打造柔性灵活的基础设施和强大的基础服务能力。这种生态系统支持快速迭代的开发和持续运营交付能力,同时注重用户体验,推动服务创新和管理变革。智慧校园的核心思想是“大平台+微应用+开放生态”,通过解耦、重构和统一运维监控,实现服务复用和深度融合,促进业务的快速迭代和自我演化。 智慧校园的总体框架包括多端协同,即“端”,它强调以人为中心,全面感知和捕获行为数据。这涉及到智能感知设备、超级APP、校园融合门户等,实现一“码”或“脸”通行,提供线上线下服务端的无缝连接。此外,中台战略是智慧校园建设的关键,包括业务中台和数据中台,它们支持教育资源域、教学服务域等多个领域,实现业务的深度融合和数据的全面治理。 在技术层面,智慧校园的建设需要分期进行,逐步解耦应用,优先发展轻量级应用,并逐步覆盖更多业务场景。技术升级路径包括业务数据化、数据业务化、校园设施智联化等,利用IoT/5G等技术实现设备的泛在互联,并通过人工智能与物联网技术的结合,建设智联网。这将有助于实现线上线下一网通办,提升校园安全和学习生活体验,同时支持人才培养改革和后勤管理的精细化。 智慧校园的建设不仅仅是技术的升级,更是对教育模式和管理方式的全面革新。通过构建开放、共享的信息化生态系统,智慧校园能够更好地适应快速变化的教育需求,提供更加个性化和高效的服务,推动教育创新和人才培养的高质量发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值