2021-02-23-膜你赛 计算器

2021-02-23-膜你赛

T1.计算器

\(n\)个计算器,它们构成了一棵树。每个计算器有两个参数\((a,b)\),如果你输入\(x\),计算器就会输出\(ax+b\)

现在你需要选一条从根到叶子的链,设它们分别为\(u1,u2...,uk\)你会把\(1\)输入\(u1\),然后把\(u1\)的输出输入\(u2\)……最后把\(u2\)的输出输入\(u3\),得到一个输出。

你需要最大化这个输出。注意本题不取模

保证参数\(a,b\) 都是在给定范围内均匀随机的\((a,b\in [1,9])\)但是树不是随机的

考试时发现撞车了,这道题如果放在序列上就是我晚自习\(yy\)的一道题的弱化版

数据规模为\(5*10^5\), 已成为常见\(log^2n(\sqrt n)\)算法

看见\(a,b\)随机,可以考虑乱搞先打它一个暴力,再进行优化,最后证明期望时间复杂度

如果不考虑结果爆掉,我们可以想到\(O(n)\)的枚举每个叶子,计算其结果,加上高精共\(O(n^3)\)

存在过的可能

考虑进行优化。我们可以发现如果进行逆推,当\(2\)个叶子退到同一个结点时,如果一者的\(a,b\)均大于另一者,则我们可以排除掉后者

所以我们考虑分治。先将叶子按\(dfs\)序排序,假设我们要求出第\([l,r]\)个叶子中可能为答案的叶子,我们可以先求出\([l,mid]\)\([mid+1,r]\)中可能的叶子,再合并

所以算法流程为

\[\begin{cases} &返回第l个节点&l=r\\ &求解[l,mid],[mid+1,r]。将左右可能结果均逆推至lca_{[l,r]},筛去不可能节点&l\not =r \end{cases} \]

下面便是愉快的计算期望时间复杂度环节

\[假设节点x处其子树内有n个可行叶子(忽略叶子不够)\\ 可以知道,二叶子排除彼此的概率为\frac{1}{2}\\ 所以E(n)=\sum_{i=1}^\infty \frac{1}{2^i}=2\\ \]

所以期望总上行次数为\(O(n)\),也就是说每次合并可能节点时期望只会合并至\(2\)个,是不是很奇妙?

\[合并可行情况处时间复杂度:T(n)= \begin{cases} &1&n=1\\ &2T(\frac{n}{2})+n\log n&n\not =1 \end{cases} \]

\[跳重链处时间复杂度:T(n)= \begin{cases} &1&n=1\\ &T(\frac{n}{2})+n\log^2 n&n\not =1 \end{cases} \]

所以期望时间复杂度为\(O(nlog^2n)\)

\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.}\)

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;char k;bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
const int mod=998244353,g=3,invg=332748118;
int qkpow(int n,int m){
	if(!m)return 1;
	ll t=qkpow(n,m>>1);
	t=t*t%mod;
	if(m&1)t=t*n%mod;
	return t;
}
int r[1000005];
ll invx[1000005],gp[32005],hgp[32005],igp[32005],higp[32005];
void init(int N=32000){
	gp[0]=1;
	for(int i=1;i<=N;++i)gp[i]=gp[i-1]*g%mod;
	hgp[0]=1;
	for(int i=1;i<=N;++i)hgp[i]=hgp[i-1]*gp[N]%mod;
	igp[0]=1;
	for(int i=1;i<=N;++i)igp[i]=igp[i-1]*invg%mod;
	higp[0]=1;
	for(int i=1;i<=N;++i)higp[i]=higp[i-1]*igp[N]%mod;
}
int Pow(int x,int y){
	if(x==g)return gp[y%32000]*hgp[y/32000]%mod;
	return igp[y%32000]*higp[y/32000]%mod;
}
void NTT(int *a,int n,bool ty){
	int L=log2(n);r[0]=0;
	for(int i=0;i<n;++i){
		r[i]=(r[i>>1]>>1)|((i&1)<<L-1);
		if(r[i]>i)swap(a[r[i]],a[i]);
	}
	for(int i=1;i<n;i<<=1){
		int w=Pow(ty?g:invg,(mod-1)/(i<<1));
		for(int j=0,o=i<<1;j<n;j+=o)
			for(int k=0,u=1;k<i;++k,u=1ll*u*w%mod){
				int x=a[j+k],y=1ll*a[i+j+k]*u%mod;
				a[j+k]=(x+y)%mod;a[i+j+k]=(x-y+mod)%mod;
			}
	}
}
struct A{
	vector<int>x;
	A(int n=0):x(n){}
	~A(){vector<int>().swap(x);}
	void resize(int n){x.resize(n);}
	int size()const{return x.size();}
	int& operator [](int v){return x[v];}
	int ret(int v)const{return x[v];}
	void push_back(int v){x.push_back(v);}
	void clear(){x.clear();}
	A& operator +=(const A &b){
		int w=min(size(),b.size());
		for(int i=0;i<w;++i)
			x[i]+=b.ret(i);
		for(int i=w;i<b.size();++i)x.push_back(b.ret(i));
		w=x.size();
		for(int i=0;i+1<w;++i){
			int t=x[i]/10;
			x[i+1]+=t;
			x[i]-=(t<<3)+(t<<1);
		}--w;
		while(x[w]>9)x.push_back(x[w]/10),x[w]%=10,++w;
		return *this;
	}
	A& operator =(ll v){
		x.clear();int u=v;
		do v/=10,x.push_back(u-((v<<3)+(v<<1)));while(u=v);
		return *this;
	}
	bool operator <(const A& b)const{
		if(size()!=b.size())return size()<b.size();
		for(int i=size();i--;)
			if(x[i]!=b.ret(i))return x[i]<b.ret(i);
		return 0;
	}
	bool operator >(const A& b){return b<*this;}
	bool operator ==(const A& b){return !(*this<b||b<*this);}
	bool operator !=(const A& b){return !(*this==b);}
	bool operator <=(const A& b){return !(*this>b);}
	bool operator >=(const A& b){return !(*this<b);}
	A& operator *=(const A& y){
		int s=1,n=size()+y.size();
		while(s<n)s<<=1;
		int *a=new int[s](),*b=new int[s]();
		for(int i=0;i<size();++i)a[i]=x[i];
		for(int i=0;i<y.size();++i)b[i]=y.ret(i);
		NTT(a,s,1);NTT(b,s,1);
		for(int i=0;i<s;++i)a[i]=1ll*a[i]*b[i]%mod;
		NTT(a,s,0);ll tv=invx[s];
		for(int i=0;i<size();++i)x[i]=a[i]*tv%mod;
		for(int i=size();i<n;++i)x.push_back(a[i]*tv%mod);
		delete[] a;delete[] b;
		int w=size()-1,t;
		for(int i=0;i<w;++i){
			x[i+1]+=t=x[i]/10;
			x[i]-=(t<<3)+(t<<1);
		}
		while(x[w]>9)x.push_back(t=x[w]/10),x[w]-=(t<<3)+(t<<1),++w;
		while(x.size()>1&&!x.back())x.pop_back();
		return *this;
	}
	A operator *(const A& y){A v=*this;v*=y;return v;}
	A operator +(const A& y){A v=*this;v+=y;return v;}
};
struct IO{
	IO& operator << (A b){
		for(int i=b.size();i--;)putchar(b[i]^'0');
		return *this;
	} 
	IO& operator << (const char* b){
		printf("%s",b);
		return *this;
	} 
	IO& operator >> (A &b){
		b=read;
		return *this;
	} 
}pr;
vector<int>G[500005];
int dfn[500005],s,siz[500005],fa[500005],son[500005],top[500005],h[500005],rk[500005];
vector<int>hv;
void dfs(int n){siz[n]=1;h[n]=h[fa[n]]+1;
	for(int i=0;i<G[n].size();++i)
		if(G[n][i]!=fa[n]){
			fa[G[n][i]]=n,dfs(G[n][i]);
			siz[n]+=siz[G[n][i]];
			if(siz[G[n][i]]>siz[son[n]])son[n]=G[n][i];
		}
	if(G[n].size()==1&&n!=1)hv.push_back(n);
}
void dfs1(int n,int x){
	top[n]=x;rk[dfn[n]=++dfn[0]]=n;
	if(son[n])dfs1(son[n],x);
	for(int i=0;i<G[n].size();++i)
		if(G[n][i]!=son[n]&&G[n][i]!=fa[n])
			dfs1(G[n][i],G[n][i]);
}
struct B{
	A x,y;
	B& operator *=(const B& b){
		x*=b.x;y*=b.x;y+=b.y;
		return *this;
	}
	B operator *(const B& b){B w=*this;w*=b;return w;}
}va[2000005];
B a[500005];
bool cmp(int x,int y){return dfn[x]<dfn[y];}
void build(int l,int r,int d){
	if(l==r)va[d]=a[rk[l]];
	else{
		int mid=l+r>>1;
		build(l,mid,d<<1);
		build(mid+1,r,d<<1|1);
		if(top[rk[l]]==top[rk[r]])
			va[d]=va[d<<1]*va[d<<1|1];
	}
}
B query(int l,int r,int tl,int tr,int d){
	if(l==tl&&r==tr)return va[d];
	int mid=tl+tr>>1;
	if(r<=mid)return query(l,r,tl,mid,d<<1);
	if(mid<l)return query(l,r,mid+1,tr,d<<1|1);
	return query(l,mid,tl,mid,d<<1)*query(mid+1,r,mid+1,tr,d<<1|1);
}
int Lca(int u,int v){
	int tu=top[u],tv=top[v];
	while(tu!=tv){
		if(h[tu]<h[tv])swap(u,v),swap(tu,tv);
		tu=top[u=fa[tu]];
	}
	return h[u]>h[v]?v:u;
}
B up(int x,int v){
	int tx=fa[top[x]];
	B t;bool fl=0;
	if(!v)return t.x=1,t.y=0,t;
	while(h[x]-h[tx]<v){
		v-=h[x]-h[tx];
		if(fl)t=query(dfn[top[x]],dfn[x],1,s,1)*t;
		else t=query(dfn[top[x]],dfn[x],1,s,1);
		fl=1;tx=fa[top[x=tx]];
	}
	if(fl)t=query(dfn[x]-v+1,dfn[x],1,s,1)*t;
	else t=query(dfn[x]-v+1,dfn[x],1,s,1);
	return t;
}
vector<B>utx[20],uty[20];int cnt;
void solve(int l,int r,bool fl,vector<B>&tem,int *tv=NULL){
	++cnt;vector<B>&tx=utx[cnt],&ty=uty[cnt];
	if(!tv)tv=new int;
	if(l==r){
		tem.push_back(a[hv[l]]);
		*tv=hv[l];
	}
	else{
		int mid=l+r>>1,x,y;
		solve(l,mid,0,tx,&x);solve(mid+1,r,0,ty,&y);
		int la=Lca(x,y);
		B u=up(fa[x],h[x]-h[la]),v=up(fa[y],h[y]-h[la]);
		for(int i=0;i<tx.size();++i)tx[i]=u*tx[i];
		for(int i=0;i<ty.size();++i)ty[i]=v*ty[i];
		for(int i=0,j=0;i<tx.size()||j<ty.size();)
			if(j==ty.size()||i!=tx.size()&&tx[i].x<ty[j].x){
				while(tem.size()&&tem.back().y<=tx[i].y)tem.pop_back();
				tem.push_back(tx[i]);++i;
			}else{
				while(tem.size()&&tem.back().y<=ty[j].y)tem.pop_back();
				tem.push_back(ty[j]);++j;
			}*tv=la;
	}tx.clear();ty.clear();--cnt;
	if(fl){
		int ux=h[*tv]-1;
		B u=up(fa[*tv],ux);
		for(int i=0;i<tem.size();++i)tem[i]=u*tem[i];
	}
}
vector<B>x;
A Max(A x,A y){return x<y?y:x;}
int main(){//fre("calc");
	s=read;
	if(s==1)return printf("%lld",read+read),0;
	invx[1]=1;init();
	for(int i=2;i<=(s<<1|1);++i)
		invx[i]=(mod-mod/i*invx[mod%i])%mod;
	for(int i=1;i<=s;++i)
		a[i].x=read,a[i].y=read;
	for(int i=1;i<s;++i){
		int u=read,v=read;
		G[u].push_back(v);
		G[v].push_back(u);
	}dfs(1);dfs1(1,1);build(1,s,1);
	solve(0,hv.size()-1,1,x);
	A ans(0);
	for(int i=0;i<x.size();++i)
		ans=Max(ans,x[i].x+x[i].y);
	pr<<ans;
	return 0;
}


posted @ 2021-02-26 17:18  ファイナル  阅读(116)  评论(2)    收藏  举报