loj#2251. 「ZJOI2017」树状数组(二维数点,树套树维护概率)

先放代码,日后更。(*2)

===========================2018.3.21UPD===========================
题面在这里

做法

容易发现只要将query的 l1,r l − 1 , r 改成 r+1,l r + 1 , l 就是正确的了。所以最后答案之和 l1,r l − 1 , r 这两个点的奇偶性是否相同有关。问题转化为维护两个位置的奇偶性相同的概率,二维数点,可以用树套树解决。注意 l=1 l = 1 的情况需要注意一下。

代码

为什么我的代码跑得那么慢!!
人傻自带大常数qwq。

/*
*   转化题意;
*   二维数点;
*   分类讨论;
*   概率论;
*/
#include
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define N 100010
#define M 40000010
#define ll long long
#define mod 998244353
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
int n,m,ans,tot,rt[N<<2],ls[M],rs[M],val[M];
int ksm(int x,int p){
    int ret=1;
    for (; p; p>>=1,x=(ll)x*x%mod) if (p&1) ret=(ll)ret*x%mod;
    return ret;
}
int inv(int x){
    return ksm(x,mod-2);
}
int merge(int x,int y){
    return ((ll)x*y%mod+(ll)(1+mod-x)*(1+mod-y)%mod)%mod;
}
void upd2(int &o,int l,int r,int x,int y,int p){
    if (!o) o=++tot,val[o]=1;
    if (x<=l && r<=y){
        val[o]=merge(val[o],p);
        return;
    }
    int mid=l+r>>1;
    if (x<=mid) upd2(ls[o],l,mid,x,y,p);
    if (y>mid) upd2(rs[o],mid+1,r,x,y,p);
}
void qry2(int o,int l,int r,int x){
    if (!o) return;
    ans=merge(ans,val[o]);
    if (l==r) return;
    int mid=l+r>>1;
    if (x<=mid) qry2(ls[o],l,mid,x); else qry2(rs[o],mid+1,r,x);
}
void upd(int o,int l,int r,int x,int y,int xx,int yy,int p){
    if (x<=l && r<=y){
        upd2(rt[o],0,n,xx,yy,p);
        return;
    }
    int mid=l+r>>1;
    if (x<=mid) upd(lc,l,mid,x,y,xx,yy,p);
    if (y>mid) upd(rc,mid+1,r,x,y,xx,yy,p);
}
void qry(int o,int l,int r,int x,int y){
    if (rt[o]) qry2(rt[o],0,n,y);
    if (l==r) return;
    int mid=l+r>>1;
    if (x<=mid) qry(lc,l,mid,x,y); else qry(rc,mid+1,r,x,y);
}
int main(){
    n=read(); m=read(); int now=0;
    while (m--){
        int opt=read(),l=read(),r=read();
        if (opt==1){//修改
            int p=inv(r-l+1),p2=2ll*p%mod;//二维区间更新
            upd(1,0,n,0,l-1,l,r,1+mod-p);
            if (r1,0,n,l,r,r+1,n,1+mod-p);
            upd(1,0,n,l,r,l,r,1+mod-p2);
            now^=1;
        } else{
            ans=1;
            if (l==1 && (now&1)){ qry(1,0,n,0,r); ans=(1+mod-ans)%mod; }
            else qry(1,0,n,l-1,r);//二维单点查询
            printf("%d\n",ans);
        }
    }
    return 0;
}

你可能感兴趣的:(线段树,树套树,loj)