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;
}
posted @ 2018-05-20 19:49  poorpool  阅读(464)  评论(0编辑  收藏  举报