• 【BZOJ5461】 【PKUWC2018】—Minimax(线段树合并优化dp)


    传送门

    发现其实就是左右2棵子树,左儿子选到某个值的概率就是
    选最大值的概率*右儿子的值比它小的概率
    ++选最小值的概率*右儿子的值比他大的概率

    右儿子类似

    由于保证所有值不都相等
    然后上线段树合并mergemerge的时候dpdp一下就完了

    复杂度O(nlogn)O(nlogn)

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
    	static char ibuf[RLEN],*ib,*ob;
    	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    	return (ib==ob)?EOF:*ib++;
    }
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    const int mod=998244353;
    const int N=500005;
    inline int add(int a,int b){
    	return a+b>=mod?a+b-mod:a+b;
    }
    inline void selfadd(int &a,int b){
    	a=add(a,b);
    }
    inline int dec(int a,int b){
    	return a>=b?a-b:a-b+mod;
    }
    inline int mul(int a,int b){
    	return 1ll*a*b>=mod?1ll*a*b%mod:a*b;
    }
    inline void selfmul(int &a,int b){
    	a=mul(a,b);
    }
    inline int ksm(int a,int b,int res=1){
    	for(;b;b>>=1,a=mul(a,a))if(b&1)selfmul(res,a);
    	return res;
    }
    int cnt[N],son[N][2],rt[N],val[N],pmx[N];
    int fa[N],ori[N],ans,n;
    struct node{
    	int k,p;
    	friend inline bool operator <(const node &a,const node &b){
    		return a.k<b.k;
    	}
    }q[N];int tot;
    namespace Seg{
    	#define mid ((l+r)>>1)
    	int tot,cnt,mxa,mxb;
    	int lc[N*22],rc[N*22],tag[N*22],tr[N*22];
    	void update(int &u,int l,int r,int k){
    		u=++tot,tag[u]=1,tr[u]=1;
    		if(l==r)return;
    		if(k<=mid)update(lc[u],l,mid,k);
    		else update(rc[u],mid+1,r,k);
    	}
    	inline void pushup(int u){
    		tr[u]=add(tr[lc[u]],tr[rc[u]]);
    	}
    	inline void pushnow(int u,int t){
    		selfmul(tag[u],t);
    		selfmul(tr[u],t);
    	}
    	inline void pushdown(int u){
    		if(tag[u]==1)return;
    		int &t=tag[u];
    		if(lc[u])pushnow(lc[u],t);if(rc[u])pushnow(rc[u],t);
    		t=1;
    	}
    	int merge(int r1,int r2,int g){
    		if(!r1&&!r2)return 0;
    		pushdown(r1),pushdown(r2);
    		if(!r1){
    			selfadd(mxb,tr[r2]);
    			pushnow(r2,dec(add(mxa,g),mul(2,mul(mxa,g))));
    			return r2;
    		}
    		if(!r2){
    			selfadd(mxa,tr[r1]);
    			pushnow(r1,dec(add(mxb,g),mul(2,mul(mxb,g))));;
    			return r1;
    		}
    		rc[r1]=merge(rc[r1],rc[r2],g);
    		lc[r1]=merge(lc[r1],lc[r2],g);
    		pushup(r1);return r1;
    	}
    	void dfs(int u){
    		if(!::cnt[u])return;
    		else if(::cnt[u]==1)dfs(son[u][0]),rt[u]=rt[son[u][0]];
    		else if(::cnt[u]==2){
    			dfs(son[u][0]),dfs(son[u][1]);
    			mxa=mxb=0;
    			rt[u]=merge(rt[son[u][0]],rt[son[u][1]],pmx[u]);
    		}
    	}
    	void calc(int u,int l,int r){
    		if(!tr[u])return;
    		pushdown(u);
    		if(l==r){
    			cnt++;
    			selfadd(ans,mul(mul(mul(cnt,ori[l]),tr[u]),tr[u]));
    			return;
    		}
    		calc(lc[u],l,mid),calc(rc[u],mid+1,r);
    	}
    }
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++){
    		fa[i]=read();
    		son[fa[i]][cnt[fa[i]]++]=i;
    	}
    	int inv=ksm(10000,mod-2);
    	for(int i=1;i<=n;i++){
    		int k=read();
    		if(cnt[i])pmx[i]=mul(k,inv);
    		else{q[++tot]=(node){k,i};}
    	}
    	sort(q+1,q+tot+1);
    	for(int i=1;i<=tot;i++){
    		ori[i]=q[i].k,Seg::update(rt[q[i].p],1,tot,i);
    	}
    	Seg::dfs(1);
    	Seg::calc(rt[1],1,tot);
    	cout<<ans;
    }
    
  • 相关阅读:
    java后台生成图片二维码
    layui框架下的摸索与学习
    eclipse/myeclipse中js/java的自动提示只有4个字符怎么解决
    Git日常操作指令
    node指南开发练习笔记(1)-- express
    echart全国主要城市某数据的显示
    微信公众号开发获取当前位置
    显示上传图片
    移动端Safari onclick事件兼容
    Plupload上传插件自定义图片的修改
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145564.html
Copyright © 2020-2023  润新知