今年年初的时候参加了PKUWC,结果当时这一题想了快$2h$都没有想出来....

哇我太菜啦....

昨天突然去搜了下哪里有题,发现$loj$上有于是就去做了下。

结果第一题我5分钟就把所有细节都想好了啊5555....

场上$60pts$消失...


显然,我们可以用$f[i][j]$表示节点$i$值为第$j$大的值的概率。

我们不难列出$dp$式子,$f[i][j]=f[s1][j] \times (s[s2][j-1]\times p+(s[s2][m]-s[s2][j])\times (1-p))$。

其中$s[i][j]=\sum_{k=0}{j} f[i][k]$。$s1$表示可以取到第j大的数的儿子,$s2$表示不能取到第$j$大的数的儿子。

显然,直接转移是$O(n^2)$的(我场上就写了这个)。

考虑如何进行优化。

题目中有一些特别优美的条件,比如说所有的数不会重复,树最多只有两个分叉。

如果某个树只有一个分叉的话,显然直接复制根即可,时间复杂度为$O(1)$。

考虑用线段树优化,考虑如何合并$s1$和$s2$这两棵树。

假设我们当前要合并的区间为$[l,r]$,且$x,y$分别为线段树中$s1,s2$用来表示区间$[l,r]$的节点。

对于该区间,我们用$xs1$来表示$s[s2][l-1]$,用$xs2$来表示$(s[s2][m]-s[s2][r])$。对于$s2$同理(暂且用$ys1,ys2$表示)。

递归的时候,若往线段树的左儿子递归,那么$xs2$就要加上$x$的右儿子的概率和,$ys2$同理。若线段树往右儿子递归,也同理。

然后当递归到$x$或$y$中有一个不存在时,直接用$xs1/2$,$ys1/2$更新即可。

(若$l==r$,则更新方式与上述$dp$式子相同,若$l≠r$,打个标记就行了)

考虑到线段树合并的时间复杂度为$O(n log n)$。所以这种方法是可以通过的。

完结撒花~~

 #include<bits/stdc++.h>
#define L long long
#define MOD 998244353
#define M 300005
using namespace std; L pow_mod(L x,L k){
L ans=;
while(k){
if(k&) ans=ans*x%MOD;
x=x*x%MOD; k>>=;
}
return ans;
} int lc[M*]={},rc[M*]={},root[M]={},use=;
L p[M*]={},tag[M*]={},gailv[M]={};
int l[M]={},r[M]={}; void pushdown(int x){
if(tag[x]!=){
if(lc[x]!=) tag[lc[x]]=tag[lc[x]]*tag[x]%MOD,p[lc[x]]=p[lc[x]]*tag[x]%MOD;
if(rc[x]!=) tag[rc[x]]=tag[rc[x]]*tag[x]%MOD,p[rc[x]]=p[rc[x]]*tag[x]%MOD;
tag[x]=;
}
}
void pushup(int x){p[x]=(p[lc[x]]+p[rc[x]])%MOD;} void updata(int &x,int l,int r,int k){
if(!x) {x=++use; p[x]=tag[x]=;}
if(l==r){p[x]=tag[x]=; return;}
int mid=(l+r)>>;
if(k<=mid) updata(lc[x],l,mid,k);
if(mid<k) updata(rc[x],mid+,r,k);
pushup(x);
} L nowp;
int solve(int x,int y,L xs1,L xs2,L ys1,L ys2){
if(x==&&y==) return ;
if(y==){
L upd=(xs1*nowp+xs2*(-nowp+MOD))%MOD;
tag[x]=upd*tag[x]%MOD;
p[x]=upd*p[x]%MOD;
return x;
}
if(x==){
L upd=(ys1*nowp+ys2*(-nowp+MOD))%MOD;
tag[y]=upd*tag[y]%MOD;
p[y]=upd*p[y]%MOD;
return y;
}
pushdown(x); pushdown(y);
L p1=p[lc[y]],p2=p[lc[x]];
lc[x]=solve(lc[x],lc[y],xs1,(xs2+p[rc[y]])%MOD,ys1,(ys2+p[rc[x]])%MOD);
rc[x]=solve(rc[x],rc[y],(xs1+p1)%MOD,xs2,(ys1+p2)%MOD,ys2);
pushup(x);
return x;
} void dfs(int x){
if(l[x]) dfs(l[x]);
if(r[x]) dfs(r[x]);
if(!l[x]) return;
if(!r[x]) {root[x]=root[l[x]]; return;}
nowp=gailv[x];
root[x]=solve(root[l[x]],root[r[x]],,,,);
}
L w[M]={},hh[M]={}; int m=; L ans=;
void getans(int x,L l,L r){
if(l==r){
ans=(ans+l*hh[l]%MOD*p[x]%MOD*p[x])%MOD;
return;
}
pushdown(x);
L mid=(l+r)>>;
getans(lc[x],l,mid);
getans(rc[x],mid+,r);
} int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n; scanf("%d",&n);
for(int i=;i<=n;i++){
int x; scanf("%d",&x);
if(!l[x]) l[x]=i;
else r[x]=i;
}
L inv10000=pow_mod(,MOD-);
for(int i=;i<=n;i++){
L x; scanf("%lld",&x);
if(l[i]) gailv[i]=x*inv10000%MOD;
else w[i]=x,hh[++m]=x;
}
sort(hh+,hh+m+);
for(int i=;i<=n;i++) if(w[i]){
int x; x=lower_bound(hh+,hh+m+,w[i])-hh;
updata(root[i],,m,x);
}
dfs();
getans(root[],,m);
printf("%lld\n",ans);
}

【pkuwc2018】 【loj2537】 Minmax DP+线段树合并的更多相关文章

  1. [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)

    还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...

  2. LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】

    LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...

  3. BZOJ.5461.[PKUWC2018]Minimax(DP 线段树合并)

    BZOJ LOJ 令\(f[i][j]\)表示以\(i\)为根的子树,权值\(j\)作为根节点的概率. 设\(i\)的两棵子树分别为\(x,y\),记\(p_a\)表示\(f[x][a]\),\(p_ ...

  4. 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)

    点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...

  5. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  6. P6847-[CEOI2019]Magic Tree【dp,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P6847 题目大意 \(n\)个点的一棵树上,每个时刻可以割掉一些边,一些节点上有果实表示如果在\(d_i\)时刻这 ...

  7. 洛谷P4577 [FJOI2018]领导集团问题(dp 线段树合并)

    题意 题目链接 Sol 首先不难想到一个dp,设\(f[i][j]\)表示\(i\)的子树内选择的最小值至少为\(j\)的最大个数 转移的时候维护一个后缀\(mx\)然后直接加 因为后缀max是单调不 ...

  8. BZOJ 5469: [FJOI2018]领导集团问题 dp+线段树合并

    在 dp 问题中,如果发现可以用后缀最大值来进行转移的话可以考虑去查分这个后缀最大值. 这样的话可以用差分的方式来方便地进行维护 ~ #include <bits/stdc++.h> #d ...

  9. LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并

    传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...

随机推荐

  1. ubuntu系统下安装pyspider:安装命令集合。

    本篇内容的前提是你已安装好python 3.5.在ubuntu系统中安装pyspider最大的困难是要依赖组件经常出错,特别是pycurl,但把对应的依赖组件安装好,简单了.下面直接上代码,所有的依赖 ...

  2. Json和XML解析

    NSXMLParse 关于XML,有两种解析方式,分别是SAX(Simple API for XML,基于事件驱动的解析方式,逐行解析数据,采用协议回调机制)和DOM(Document Object ...

  3. 如何修改路由器的登录IP地址?

    如何修改路由器的登录IP地址? 因为有多个路由器,为了区分不同路由器,我们可以修改它的登录IP,而且修改后,可以在连接的电脑上直观地知道所连接的是哪一台路由器 买回来的路由器,一般默认的登录地址是19 ...

  4. 20155213 2016-2017-2 《Java程序设计》第八周学习总结

    20155213 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十四章NIO与NIO2 NIO NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你 ...

  5. unidac 6.0.1 与kbmmw 的一点小摩擦

    unidac 6.0.1  出来了,虽然支持sql server 直连等新特性,但是由于内部改动比较大, 导致与kmmmw 的集成起来存在有点小问题,就是如果数据库不是interbase 或者fire ...

  6. Java 继承关系中:static,构造函数,成员变量的加载顺序

    首先看下面的例子: package simple.demo; /** * @author Administrator * @date 2019/01/03 */ public class ClassA ...

  7. python读取文件,python读取的1变成\ufeff1

    '\ufeff1' movies={} fm=open(self.path+'/movie.txt',encoding='utf-8') w2=open('./data/1.txt','a') for ...

  8. [unchecked] 对作 为原始类型Hashtable的成员的put(K,V)的调用未经过检查。。。

    问题: C:\Users\Administrator\Desktop\java\SoundApplet.java:212: 警告: [unchecked] 对作为原始类型Hashtable的成员的pu ...

  9. nodejs+express+mysql+handsontable

    介绍:做一个医疗数据分析的系统 现在看是写后端的功能,按照PHP的功能,在node上一个个实现. 1.route引用controller,controller引用model,所以会先执行model可以 ...

  10. 【TypeScript】TypeScript 学习 4——模块

    前端数据验证在改善用户体验上有很大作用,在学了之前的知识的时候,我们很可能会写出以下代码: interface StringValidator { isAcceptable(s: string): b ...