• 【uoj291】 ZJOI2017—树状数组


    http://uoj.ac/problem/291 (题目链接)

    题意

      一个写错的树状数组有多大的概率与正常树状数组得出的答案一样。

    Solution

      可以发现这个树状数组维护的是后缀和。

      所以二维线段树维护二维数点$(l,r)$,表示左端点$l$与右端点$r$被修改次数相等的几率有多大。

      对于$l=1$的情况,另外开一个普通的线段树维护,操作不用重写。

    细节

      标记可持久化,不然好像会被hack数据卡TLE?

    代码

    // uoj291
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1ll<<29)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010,MOD=998244353;
    int n,m,rt[maxn<<2],ans;
    struct node {
    	int son[2],p;
    	int& operator [] (int x) {return son[x];}
    }tr[maxn*400];
    
    LL power(LL a,LL b) {
    	LL res=1;
    	while (b) {
    		if (b&1) (res*=a)%=MOD;
    		b>>=1;(a*=a)%=MOD;
    	}
    	return res;
    }
    
    namespace D2 {
    	int sz;
    	void modify(int &k,int l,int r,int s,int t,int p) {
    		if (!k) k=++sz,tr[k].p=1;
    		if (s<=l && r<=t) {
    			tr[k].p=(1LL*tr[k].p*p%MOD+1LL*(1-tr[k].p+MOD)*(1-p+MOD)%MOD)%MOD;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if (s<=mid) modify(tr[k][0],l,mid,s,t,p);
    		if (t>mid) modify(tr[k][1],mid+1,r,s,t,p);
    	}
    	void query(int k,int l,int r,int p) {
    		if (!k) return;
    		ans=(1LL*ans*tr[k].p%MOD+1LL*(1-ans+MOD)*(1-tr[k].p+MOD)%MOD)%MOD;
    		int mid=(l+r)>>1;
    		if (p<=mid) query(tr[k][0],l,mid,p);
    		else query(tr[k][1],mid+1,r,p);
    	}
    }
    
    namespace D1 {
    	void modify(int k,int l,int r,int s1,int t1,int s2,int t2,int p) {
    		if (s1<=l && r<=t1) {
    			D2::modify(rt[k],1,n,s2,t2,p);
    			return;
    		}
    		int mid=(l+r)>>1;
    		if (s1<=mid) modify(k<<1,l,mid,s1,t1,s2,t2,p);
    		if (t1>mid) modify(k<<1|1,mid+1,r,s1,t1,s2,t2,p);
    	}
    	void query(int k,int l,int r,int s,int t) {
    		D2::query(rt[k],1,n,t);
    		if (l==r) return;
    		int mid=(l+r)>>1;
    		if (s<=mid) query(k<<1,l,mid,s,t);
    		else query(k<<1|1,mid+1,r,s,t);
    	}
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int op,l,r,i=1;i<=m;i++) {
    		scanf("%d%d%d",&op,&l,&r);
    		if (op==1) {
    			int p=power(r-l+1,MOD-2);
    			if (l!=r) D1::modify(1,1,n,l,r,l,r,(1-2*p%MOD+MOD)%MOD);
    			if (l>1) {
    				D1::modify(1,1,n,1,l-1,l,r,(1-p+MOD)%MOD);
    				D2::modify(rt[0],1,n,1,l-1,0);
    			}
    			if (r<n) {
    				D1::modify(1,1,n,l,r,r+1,n,(1-p+MOD)%MOD);
    				D2::modify(rt[0],1,n,r+1,n,0);
    			}
    			D2::modify(rt[0],1,n,l,r,p);
    		}
    		if (op==2) {
    			--l;ans=1;
    			if (!l) D2::query(rt[0],1,n,r);
    			else D1::query(1,1,n,l,r);
    			printf("%d
    ",ans);
    		}
    	}
        return 0;
    }
    
  • 相关阅读:
    redis 储存对象
    redis key 查看器
    c# 控制台程序编写RabbitMQ 生产者
    C# 使用Topshelf 构建 基于 window 服务的 RabbitMQ消费端
    asp.net webapi 使用定时任务Hangfire
    asp.net webpi 中使用 ClientHelper 发起HTTP请求
    SQL Server 导入和导出向导 未在本地计算机上注册Mircrosoft.ACE.OLEDB.12.0 提供程序
    c# 使用Linq 表达式 对查询结果分组,保留价格最低的一条
    Asp.Net s请求报传输流收到意外的 EOF 或 0 个字节
    asp.net webapi 中使用rdlc 报表
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6689712.html
Copyright © 2020-2023  润新知