码迷,mamicode.com
首页 > 其他好文 > 详细

loj2537. 「PKUWC2018」Minimax

时间:2020-07-16 00:22:06      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:tor   auto   sizeof   pre   end   clu   int   inf   ++   

题面

题意:自己看去

题解:先考虑一个暴力的树形dp。设\(f_{i,j}\)表示节点\(i\)权值为\(j\)的概率。那么对于所有有两个儿子的节点\(i\),设它的两个儿子是\(x,y\),那么对于所有在\(x\)中出现的权值\(j\),有\(f_{i,j}=f_{x,j}\times ((p_i \times \sum_{k=1}^{j-1}f_{y,k}) +((1-p_i)\times \sum_{k=j+1}^\infty f_{y,k}))\)。对于\(y\)中出现的权值也一样。由于转移方程中出现了区间和,考虑用线段树来维护这个区间和。

考虑在线段树合并的同时进行dp。考虑当前合并的两个节点是\(x,y\),区间是\([l,r]\),二者的儿子分别为\(lc_x,rc_x,lc_y,rc_y\)。那么对于当前节点,\(lc_x,rc_y\)\(rc_x,lc_y\)都会互相造成贡献。在线段树合并时记录一下这些贡献的和,然后递归到\(x,y\)的儿子进行合并。当\(x=0\)\(y=0\)时,对于一段区间的\(f\)造成的贡献就累加完了,打一个乘法标记即可。

时间复杂度:\(O(nlogn)\)。如果不离散化的话,时间复杂度就是\(O(nlogV)\)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch==‘-‘)g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
const int Mod=998244353,inv=796898467;
typedef pair<int,int>pii;
pii p[303000];
vector<int>e[303000];
int n,m,now,ans,fa[303000],a[303000],xu[303000],b[303000];
int tot,d[303000],root[303000],lc[10100000],rc[10100000],w[10100000],tag[10100000];
I add(int &x,int y){(x+=y)>=Mod?x-=Mod:0;}
IN Plus(int x,int y){(x+=y)>=Mod?x-=Mod:0;return x;}
IN Pow(int x,int y=Mod-2){
	re res=1;
	while(y){
		if(y&1)res=(ll)res*x%Mod;
		x=(ll)x*x%Mod;
		y>>=1;
	}
	return res;
}
I D_2(int x){
	if(e[x].empty())return p[++m]=make_pair(a[x],x),void();
	for(auto d:e[x])D_2(d);
}
#define lt lc[k],l,mid
#define rt rc[k],mid+1,r
I mul(int x,int v){
	if(!x)return;
	w[x]=(ll)w[x]*v%Mod;tag[x]=(ll)tag[x]*v%Mod;
}
I push_down(int x){
	mul(lc[x],tag[x]);mul(rc[x],tag[x]);tag[x]=1;
}
I modi(int &k,int l,int r,int x){
	k=++tot;w[k]=tag[k]=1;
	if(l==r)return;
	re mid=(l+r)>>1;
	if(x<=mid)modi(lt,x);
	else modi(rt,x);
}
IN merge(int x,int y,int vx,int vy){
	if(!x||!y){
//		cout<<"!"<<vx<<" "<<vy<<endl;
		if(y)mul(y,vy);
		if(x)mul(x,vx);	
		return x+y;
	}
	push_down(x);push_down(y);
	re val[2][2];val[0][0]=w[lc[x]];val[0][1]=w[rc[x]];val[1][0]=w[lc[y]];val[1][1]=w[rc[y]];
	lc[x]=merge(lc[x],lc[y],(vx+(ll)val[1][1]*(Mod+1-now)%Mod)%Mod,(vy+(ll)val[0][1]*(Mod+1-now)%Mod)%Mod);
	rc[x]=merge(rc[x],rc[y],(vx+(ll)val[1][0]*now%Mod)%Mod,(vy+(ll)val[0][0]*now%Mod)%Mod);
	w[x]=Plus(w[lc[x]],w[rc[x]]);
	return x;
}
I damage(int k,int l,int r){
	if(l==r)return d[l]=w[k],void();
	push_down(k);
	re mid=(l+r)>>1;
	damage(lt);damage(rt);
}
I D_1(int x){
	if(e[x].empty()){
		modi(root[x],1,m,b[x]);
//		cout<<"A"<<b[x]<<endl;
		return;
	}
	root[x]=0;
	for(auto d:e[x]){
		D_1(d);
		if(!root[x])root[x]=root[d];
		else now=(ll)a[x]*inv%Mod,root[x]=merge(root[x],root[d],0,0);
	}
//	assert(!w[0]);
}
int main(){
	read(n);
	F(i,1,n)read(fa[i]),e[fa[i]].emplace_back(i);
	F(i,1,n)read(a[i]);
	D_2(1);sort(p+1,p+1+m);F(i,1,m)b[p[i].second]=i;
	D_1(1);damage(root[1],1,m);
	F(i,1,m)add(ans,(ll)i*p[i].first%Mod*d[i]%Mod*d[i]%Mod);
	printf("%d",ans);
	return 0;
}
/*
3
0 1 1
5000 1 2
*/

loj2537. 「PKUWC2018」Minimax

标签:tor   auto   sizeof   pre   end   clu   int   inf   ++   

原文地址:https://www.cnblogs.com/Purple-wzy/p/13308409.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!