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;
}
因果乃旋转纺车,光彩之多面明镜
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存

浙公网安备 33010602011771号