zoukankan      html  css  js  c++  java
  • 【pkuwc2018】 【loj2537】 Minmax DP+线段树合并

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

    哇我太菜啦....

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

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

    场上$60pts$消失...


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

    我们不难列出$dp$式子,$f[i][j]=f[s1][j] imes (s[s2][j-1] imes p+(s[s2][m]-s[s2][j]) imes (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)$。所以这种方法是可以通过的。

    完结撒花~~

      1 #include<bits/stdc++.h>
      2 #define L long long
      3 #define MOD 998244353
      4 #define M 300005
      5 using namespace std;
      6 
      7 L pow_mod(L x,L k){
      8     L ans=1;
      9     while(k){
     10         if(k&1) ans=ans*x%MOD;
     11         x=x*x%MOD; k>>=1;
     12     }
     13     return ans;
     14 }
     15 
     16 int lc[M*20]={0},rc[M*20]={0},root[M]={0},use=0;
     17 L p[M*20]={0},tag[M*20]={0},gailv[M]={0};
     18 int l[M]={0},r[M]={0};
     19 
     20 void pushdown(int x){
     21     if(tag[x]!=1){
     22         if(lc[x]!=0) tag[lc[x]]=tag[lc[x]]*tag[x]%MOD,p[lc[x]]=p[lc[x]]*tag[x]%MOD;
     23         if(rc[x]!=0) tag[rc[x]]=tag[rc[x]]*tag[x]%MOD,p[rc[x]]=p[rc[x]]*tag[x]%MOD;
     24         tag[x]=1;
     25     }
     26 }
     27 void pushup(int x){p[x]=(p[lc[x]]+p[rc[x]])%MOD;}
     28 
     29 void updata(int &x,int l,int r,int k){
     30     if(!x) {x=++use; p[x]=tag[x]=1;}
     31     if(l==r){p[x]=tag[x]=1; return;} 
     32     int mid=(l+r)>>1;
     33     if(k<=mid) updata(lc[x],l,mid,k);
     34     if(mid<k) updata(rc[x],mid+1,r,k);
     35     pushup(x);
     36 }
     37 
     38 L nowp;
     39 int solve(int x,int y,L xs1,L xs2,L ys1,L ys2){
     40     if(x==0&&y==0) return 0;
     41     if(y==0){
     42         L upd=(xs1*nowp+xs2*(1-nowp+MOD))%MOD;
     43         tag[x]=upd*tag[x]%MOD;
     44         p[x]=upd*p[x]%MOD;
     45         return x;
     46     }
     47     if(x==0){
     48         L upd=(ys1*nowp+ys2*(1-nowp+MOD))%MOD;
     49         tag[y]=upd*tag[y]%MOD;
     50         p[y]=upd*p[y]%MOD;
     51         return y;
     52     }
     53     pushdown(x); pushdown(y);
     54     L p1=p[lc[y]],p2=p[lc[x]];
     55     lc[x]=solve(lc[x],lc[y],xs1,(xs2+p[rc[y]])%MOD,ys1,(ys2+p[rc[x]])%MOD);
     56     rc[x]=solve(rc[x],rc[y],(xs1+p1)%MOD,xs2,(ys1+p2)%MOD,ys2);
     57     pushup(x);
     58     return x;
     59 }
     60 
     61 void dfs(int x){
     62     if(l[x]) dfs(l[x]);
     63     if(r[x]) dfs(r[x]);
     64     if(!l[x]) return;
     65     if(!r[x]) {root[x]=root[l[x]]; return;}
     66     nowp=gailv[x];
     67     root[x]=solve(root[l[x]],root[r[x]],0,0,0,0);
     68 }
     69 L w[M]={0},hh[M]={0}; int m=0;
     70 
     71 L ans=0;
     72 void getans(int x,L l,L r){
     73     if(l==r){
     74         ans=(ans+l*hh[l]%MOD*p[x]%MOD*p[x])%MOD;
     75         return;
     76     }
     77     pushdown(x);
     78     L mid=(l+r)>>1;
     79     getans(lc[x],l,mid);
     80     getans(rc[x],mid+1,r);
     81 }
     82 
     83 int main(){
     84     //freopen("in.txt","r",stdin);
     85     //freopen("out.txt","w",stdout);
     86     int n; scanf("%d",&n);
     87     for(int i=1;i<=n;i++){
     88         int x; scanf("%d",&x);
     89         if(!l[x]) l[x]=i;
     90         else r[x]=i;
     91     }
     92     L inv10000=pow_mod(10000,MOD-2);
     93     for(int i=1;i<=n;i++){
     94         L x; scanf("%lld",&x);
     95         if(l[i]) gailv[i]=x*inv10000%MOD;
     96         else w[i]=x,hh[++m]=x;
     97     }
     98     sort(hh+1,hh+m+1);
     99     for(int i=1;i<=n;i++) if(w[i]){
    100         int x; x=lower_bound(hh+1,hh+m+1,w[i])-hh;
    101         updata(root[i],1,m,x);
    102     }
    103     dfs(1);
    104     getans(root[1],1,m);
    105     printf("%lld
    ",ans);
    106 }

     

  • 相关阅读:
    SRM 574 250 DIV2
    SRM 575 250 DIV2
    SRM 577 250 DIV2
    20181211-python1119作业郭恩赐
    20181207作业-郭恩赐
    python1119-20181206作业-郭恩赐提交
    python1119-20181205作业-郭恩赐提交
    python1119作业1-郭恩赐提交
    py1119_Linux学习_第二周总结
    小白都能看懂的block
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9115544.html
Copyright © 2011-2022 走看看