zoukankan      html  css  js  c++  java
  • loj2537 「PKUWC 2018」Minimax

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

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

    50 分 yy 做法

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

    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;
    }
    
  • 相关阅读:
    038 Count and Say 数数并说
    037 Sudoku Solver 解数独
    036 Valid Sudoku 有效的数独
    035 Search Insert Position 搜索插入位置
    bzoj1202 [HNOI2005]狡猾的商人
    USACO45 lights 电灯(折半搜索)
    USACO44 TimeTravel 时间旅行(链表)
    USACO35 翻转奶牛(尺取法)
    bzoj1833: [ZJOI2010]count 数字计数&&USACO37 Cow Queueing 数数的梦(数位DP)
    USACO26 moofest 奶牛集会(归并排序)
  • 原文地址:https://www.cnblogs.com/poorpool/p/9064322.html
Copyright © 2011-2022 走看看