loj2537 「PKUWC 2018」Minimax

pkusc 快到了……做点题涨涨 rp。

初见时 yy 了一个类似于归并的东西,\(O(n^2)\),50 分。

50 分 yy 做法

对于一个点,枚举他能到达的权值(假设这个权值在左子树,在右子树是一样的),选上这个点的概率就是“在左子树选上这个点的概率 \(\times\) (选择子结点最大值的概率 \(\times\) 右子树选出比这个点小的点的概率和+选择子结点最小值的概率 \(\times\) 右子树选出比这个点大的点的概率和)”。

100 分

我们发现,瓶颈在于合并。我们先想到启发式合并,然后就不会了。

我们又想到线段树合并。这里就参考ref这里就可以了。

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int n, uu, num[300005], bb, rot[300005], tot, maxa, maxb, ans;
const int mod=998244353;
struct Node{
    int l, r, v;
}nd[300005];
struct SGTNode{
    int l, r, v, t;
}sgt[5000005];
int ksm(int a, int b){
    int re=1;
    while(b){
        if(b&1) re = (ll)re * a % mod;
        a = (ll)a * a % mod;
        b >>= 1;
    }
    return re;
}
void insert(int &x, int l, int r, int v){
    x = ++tot;
    sgt[x].v = sgt[x].t = 1;
    if(l==r)    ;
    else{
        int mid=(l+r)>>1;
        if(v<=mid)  insert(sgt[x].l, l, mid, v);
        else    insert(sgt[x].r, mid+1, r, v);
    }
}
void pushDown(int x){
    if(!x || sgt[x].t<=1)   return ;
    sgt[sgt[x].l].t = (ll)sgt[sgt[x].l].t * sgt[x].t % mod;
    sgt[sgt[x].r].t = (ll)sgt[sgt[x].r].t * sgt[x].t % mod;
    sgt[x].v = (ll)sgt[x].v * sgt[x].t % mod;
    sgt[x].t = 1;
}
int merge(int x, int y, int p){
    if(!x && !y)    return 0;
    pushDown(x); pushDown(y);
    if(!y){
        maxa = (maxa + sgt[x].v) % mod;
        sgt[x].t = ((maxb+p)%mod-(ll)2*maxb*p%mod+mod) % mod;
        pushDown(x);
        return x;
    }
    if(!x){
        maxb = (maxb + sgt[y].v) % mod;
        sgt[y].t = ((maxa+p)%mod-(ll)2*maxa*p%mod+mod) % mod;
        pushDown(y);
        return y;
    }
    sgt[x].r = merge(sgt[x].r, sgt[y].r, p);
    sgt[x].l = merge(sgt[x].l, sgt[y].l, p);
    sgt[x].v = (sgt[sgt[x].l].v + sgt[sgt[x].r].v) % mod;
    return x;
}
void dfs(int x){
    if(!nd[x].l)
        insert(rot[x], 1, bb, nd[x].v);
    else if(!nd[x].r){
        dfs(nd[x].l);
        rot[x] = rot[nd[x].l];
    }
    else{
        dfs(nd[x].l);
        dfs(nd[x].r);
        maxa = maxb = 0;
        rot[x] = merge(rot[nd[x].l], rot[nd[x].r], nd[x].v);
    }
}
void getAns(int x, int l, int r){
    if(!x)  return ;
    pushDown(x);
    if(l==r)
        ans = (ans + (ll)l*num[l]%mod*sgt[x].v%mod*sgt[x].v%mod) % mod;
    else{
        int mid=(l+r)>>1;
        getAns(sgt[x].l, l, mid);
        getAns(sgt[x].r, mid+1, r);
    }
}
int main(){
    cin>>n;
    for(int i=1; i<=n; i++){
        scanf("%d", &uu);
        if(nd[uu].l)    nd[uu].r = i;
        else    nd[uu].l = i;
    }
    int inv=ksm(10000, mod-2);
    for(int i=1; i<=n; i++){
        scanf("%d", &uu);
        if(nd[i].l) nd[i].v = (ll)uu * inv % mod;
        else{
            nd[i].v = uu;
            num[++bb] = uu;
        }
    }
    sort(num+1, num+1+bb);
    bb = unique(num+1, num+1+bb) - (num + 1);
    for(int i=1; i<=n; i++)
        if(!nd[i].l)
            nd[i].v = lower_bound(num+1, num+1+bb, nd[i].v) - num;
    dfs(1);
    getAns(rot[1], 1, bb);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/poorpool/p/9064322.html