LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]
思路
首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率。
假设\(w\)来自\(v1\)的子树,那么有
\]
其中\(p\)表示\(x\)选较小权值的概率。
由于每个点的状态数只有子树中的叶子个数,可以考虑线段树合并来优化这一DP过程。
merge(k1,k2,l,r)函数中传进去几个参数:\(v1\)和\(v2\)分别在\([1,l-1]\)的权值和&在\([r+1,n]\)的权值和。当某一个节点为0时就整个子树打乘法tag。
代码
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 303300
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
inline ll MOD(ll x){return x-((mod-x)>>31&mod);}
int n;
int w[sz],_w[sz];
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
int son[sz];
int root[sz],cc;
#define Tree sz*30
int ls[Tree],rs[Tree];
ll val[Tree],sum[Tree],tag[Tree];
#define lson ls[k],l,mid
#define rson rs[k],mid+1,r
void Mul(int k,ll w){tag[k]=tag[k]*w%mod;sum[k]=sum[k]*w%mod;val[k]=val[k]*w%mod;}
void pushup(int k){sum[k]=MOD(sum[ls[k]]+sum[rs[k]]);}
void pushdown(int k)
{
if (tag[k]==1) return;
ls[k]&&(Mul(ls[k],tag[k]),0);
rs[k]&&(Mul(rs[k],tag[k]),0);
tag[k]=1;
}
int merge(int k1,int k2,int l,int r,ll pre1,ll suf1,ll pre2,ll suf2,ll p)
{
if (k1+k2==0) return 0;
if (!k1||!k2)
{
if (!k1) swap(k1,k2),swap(pre1,pre2),swap(suf1,suf2);
Mul(k1,MOD(p*suf2%mod+(mod+1-p)*pre2%mod));
return k1;
}
pushdown(k1);pushdown(k2);
int mid=(l+r)>>1,k=++cc;tag[k]=1;
ll L1=sum[ls[k1]],R1=sum[rs[k1]],L2=sum[ls[k2]],R2=sum[rs[k2]];
ls[k]=merge(ls[k1],ls[k2],l,mid,pre1,MOD(suf1+R1),pre2,MOD(suf2+R2),p);
rs[k]=merge(rs[k1],rs[k2],mid+1,r,MOD(pre1+L1),suf1,MOD(pre2+L2),suf2,p);
pushup(k);
return k;
}
void insert(int &k,int l,int r,int x)
{
k=++cc;tag[k]=1;
if (l==r) return (void)(sum[k]=val[k]=1);
int mid=(l+r)>>1;
if (x<=mid) insert(ls[k],l,mid,x);
else insert(rs[k],mid+1,r,x);
pushup(k);
}
ll ans;
void getans(int k,int l,int r)
{
if (!k) return;
if (l==r) return (void)((ans+=1ll*l*_w[l]%mod*val[k]%mod*val[k]%mod)%=mod);
int mid=(l+r)>>1;
pushdown(k);
getans(ls[k],l,mid);getans(rs[k],mid+1,r);
}
void dfs(int x)
{
if (!son[x]) return insert(root[x],1,n,w[x]);
int v1=0,v2=0;
go(x) dfs(edge[i].t),(v1?v2:v1)=edge[i].t;
if (!v2) root[x]=root[v1];
else root[x]=merge(root[v1],root[v2],1,n,0,0,0,0,w[x]);
}
int main()
{
file();
read(n);
int x;read(x);
rep(i,2,n) read(x),make_edge(x,i),son[x]++;
x=0;
rep(i,1,n) { read(w[i]); if (!son[i]) _w[++x]=w[i]; }
sort(_w+1,_w+x+1);x=unique(_w+1,_w+x+1)-_w-1;
rep(i,1,n)
if (!son[i]) w[i]=lower_bound(_w+1,_w+x+1,w[i])-_w;
else w[i]=(10000-w[i])*inv(10000)%mod;
dfs(1);
getans(root[1],1,n);
cout<<ans;
return 0;
}
LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]的更多相关文章
- LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】
LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...
- loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】
题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\) ...
- BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)
BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...
- [PKUWC2018]Minimax [dp,线段树合并]
好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...
- 「洛谷4197」「BZOJ3545」peak【线段树合并】
题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
- 「CQOI2006」简单题 线段树
「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...
- 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并
今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来.... 哇我太菜啦.... 昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下. 结果第一题我5分钟就把所有细节都想好 ...
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
随机推荐
- JSQI网站大事表 | Website Landmark
2016-07-01 网站前身jsqi.50vip.com上线.2016-07-12 购买jsqi.org域名,替代之前的二级域名.2016-12-12 申请ChinaDMOZ收录,瞬间申请通过.20 ...
- Html 中scroll offset client 总结
HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对 ...
- my SO 链接opencv静态库一些FUCKing的笔记 opencv410 有毒
1. 2. CMake "/work/lib/opencv/ubuntu14/4.1.0" make[2]: *** No rule to make target `/usr/lo ...
- Vue中遍历数组的新方法
1.foreach foreach循环对不能使用return来停止循环 search(keyword){ var newList = [] this.urls.forEach(item =>{ ...
- selenium实现登录百度(自动识别简单验证码)
需要做的工作 0.工程结构 1.代码: ①baidu_login.py import re import os import sys import time import random from se ...
- 安卓直连SQLSEVER数据库
1.导入连接SQLSEVER的jar包:可以支持android的SQL驱动(如:jtds-1.2.7.jar) 2.编写连接数据库的工具类 import java.lang.reflect.Field ...
- nginx加入开机自启动
1.首先,在linux系统的/etc/init.d/目录下创建nginx文件,使用如下命令:(vim /etc/init.d/nginx) 2.在/etc/init.d/nginx中写入以下脚本代码 ...
- 当跨域时,js ajax 请求出现options请求
上面有文章说过http的options. 查了很久.试了很多版本的jQuery,下面这段代码在同事的机子上测试是没有问题的.正常 的请求, 一在我机子上面就会出现option,网上说先向服务器预检等. ...
- 《数据结构与算法之美》 <06>栈:如何实现浏览器的前进和后退功能?
浏览器的前进.后退功能,我想你肯定很熟悉吧? 当你依次访问完一串页面 a-b-c 之后,点击浏览器的后退按钮,就可以查看之前浏览过的页面 b 和 a.当你后退到页面 a,点击前进按钮,就可以重新查看页 ...
- excel单元格数据与文本框数据同步
Private Sub Worksheet_SelectionChange(ByVal Target As Range) ActiveSheet.Shapes().TextFrame2.TextRan ...