1 条题解

  • 0
    @ 2025-8-24 22:21:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar x_angelkawaii_x
    **

    搬运于2025-08-24 22:21:36,当前版本为作者最后更新于2020-05-05 14:53:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    • 子任务 11

    暴力搜索即可,期望得分 1010

    • 子任务 22

    T=1,c=nT=1,c=n,只有一组方案且所有点上都设置了采集器

    首先,点集中的 kk 个点对"聚焦点"产生代价 等价转化为 "聚焦点"出发选择 kk 条不经过重边的路径长度的乘积。所以一个点的总代价等于从该点出发任选 kk 条无重边路径的长度乘积之和。

    先只考虑子树,假设在计算 uu 点的答案,dfs 到以 vv 为根的子树,用 fi(0ik)f_i(0 \le i \le k) 表示在 vv 子树之前的子树中选择 ii 条路径相乘的和,gg 表示在 vv 子树中选择一条路径长度的和,那么可以这样用 gg 更新 fif_i

    f[u][0]=1;
    for(int i=0;i<k;++i)f[u][i+1]+=f[u][i]*g;
    

    之后考虑换根,从 uu 父亲 fafaf[fa][1]f[fa][1] 中扣去从 fafa 出发经过 uu 的路径贡献即可作为新的 gg 参与计算。

    复杂度 O(Tkn)\mathcal{O}(Tkn),期望得分 2525

    • 子任务 44

    考虑建立虚树,那么我们需要讨论的点有三种:虚树的结点,虚树上被压缩的二度点,不在虚树上的点

    对于虚树上的结点, dpdp 方式与 子任务 11 类似,此处不再赘述

    由于 D=0D=0,即不强制在线,所以我们可以用一个小 trick,即将查询点也当做关键点(称设置了采集器的结点为关键点)跑虚树,这样对答案不产生影响还避免了分类讨论

    复杂度 O(qklogn)\mathcal{O}(qk\log n),期望得分 5050

    • 子任务 55

    询问强制在线。

    如何判断虚树外的点?记查询点 xx 在虚树中的 dfs序 后继为 vv ,则当且仅当 vv 不在 xx 子树中时 xx 为虚树外的点,此时 xx 的答案为 00

    xx 既不是虚树结点也不是虚树外的点,则判定 xx 为二度点 ,记其 dfs序 前驱后继为 u,vu,v,则该点答案如下

    $$F[x][2]=(F[u][1]-f[v][1]-siz[v]*d(u,v)+(c-siz[v])*d(u,x))*(f[v][1]+siz[v]*d(x,v)) $$

    其中,F[x]F[x] 表示换根后的答案数组,f[x]f[x] 表示换根前的答案数组,siz[x]siz[x] 表示 xx 的子树中关键点的个数。

    时间复杂度 O(qklogn)\mathcal{O}(qk\log n),空间复杂度 O(nk)\mathcal{O}(nk),期望得分 7070

    • 子任务 66

    1kn1 \le k\le n

    先考虑如何在空间摆脱 k100k\le 100 的限制,注意到 dpdp 过程中每个点的 f[u][i]f[u][i] 数组只有 idu[u]i\le du[u] 时有意义(du[u]du[u] 表示 uu 的度),那么通过开 nn 个动态数组即可实现空间 O(n)O(n)

    但是如果按照原形式 dpdp,时间复杂度是 du2du^2 相关的,并不能通过菊花图的数据。

    观察发现,对于点 uu 来说,假设其向各棵子树(包括父子树)出发的路径长度和分别为 g1,g2,...,gmg_1,g_2,...,g_m,则答案就是在这 mm 个数中选择 1,2,...,k1,2,...,k 个数相乘的所有方案之和

    所以询问可以被化简:nn 个数中选择 kk 个数乘积的方案和为多少?

    fl,r,kf_{l,r,k} 表示 [l,r][l,r] 中选择 kk 个数的方案和,mid=l+r2mid=\frac{l+r}{2},则有

    $$f_{l,r,k}=\sum_{i=0}^{r-l+1}f_{l,mid,i}*f_{mid+1,r,r-l+1-i} $$

    明显为卷积形式,使用NTT优化即可实现时间 O(nlog2n)\mathcal{O}(n\log ^2n),空间 O(nlogn)\mathcal{O}(n\log n),可以通过本题

    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<set>
    #include<cstring>
    using namespace std;
    const int maxn=2e5+5,mod=998244353,maxk=105;
    typedef long long ll;
    int n;
    int siz[maxn],son[maxn],fa[maxn],tp[maxn],dep[maxn],dfn[maxn],tot,bck[maxn];
    struct ed{int to,w;};
    vector<ed>e1[maxn];vector<int>e2[maxn];set<int>df;
    void dfs1(int u)
    {
    	siz[u]=1;
    	for(int i=0,l=e1[u].size();i<l;++i)
    	{
    		int v=e1[u][i].to;
    		if(dep[v])continue;
    		dep[v]=(dep[u]+e1[u][i].w)%mod,fa[v]=u;
    		dfs1(v);siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int topf)
    {
    	tp[u]=topf;dfn[u]=++tot;bck[tot]=u;
    	if(!son[u])return;
    	dfs2(son[u],topf);
    	for(int i=0,l=e1[u].size();i<l;++i)
    	{
    		int v=e1[u][i].to;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    int lca(int x,int y)
    {
    	while(tp[x]!=tp[y])
    	{
    		if(dep[tp[x]]<dep[tp[y]])x^=y^=x^=y;
    		x=fa[tp[x]];	
    	}
    	return dep[x]<dep[y]?x:y;
    }
    inline int dis(int x,int y){return (dep[x]+dep[y]-(dep[lca(x,y)]<<1)+mod)%mod;}
    int p[maxn],st[maxn],top,c,k,D;
    bool cmp(const int &a,const int &b){return dfn[a]<dfn[b];}
    void ins(int u)
    {
    	if(top==1){st[++top]=u;return;}
    	int ff=lca(u,st[top]);
    	if(ff==st[top]){st[++top]=u;return;}
    	for(;dfn[st[top-1]]>=dfn[ff];--top)e2[st[top-1]].push_back(st[top]);	
    	if(ff!=st[top])e2[ff].push_back(st[top]),st[top]=ff;
    	st[++top]=u; 
    }
    namespace Poly
    {
    	const int maxm=200005;
    	const int mod=998244353;
    	typedef long long ll;
    	int q;bool fl;
    	int rev[maxm*4],bin[1<<21];
    	inline int fastpow(int x,int y,int P)
    	{
    	    int ans=1;
    	    for(;y;y>>=1,x=(ll)x*x%P) if(y&1) ans=(ll)ans*x%P;
    	    return ans;
    	}
    	inline void NTT(int *a,int n,int f)
    	{
    	    int l=bin[n];
    	    for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    	    for(int i=0;i<n;i++) if(i<rev[i]) std::swap(a[i],a[rev[i]]); 
    	    for(int i=1;i<n;i<<=1)
    	    {
    	        int wn=fastpow(3,~f?(mod-1)/(i<<1):(mod-1)-(mod-1)/(i<<1),mod);
    	        for(int j=0;j<n;j+=(i<<1))
    	        {
    	            int w=1;
    	            for(int k=0;k<i;k++,w=(ll)w*wn%mod)
    	            {
    	                int x=a[j+k],y=(ll)a[i+j+k]*w%mod;
    	                a[j+k]=(x+y)%mod,a[i+j+k]=(x-y+mod)%mod;
    	            }
    	        }
    	    }
    	    if(f==-1)
    	    {
    	        int inv=fastpow(n,mod-2,mod);
    	        for(int i=0;i<n;i++) a[i]=(ll)a[i]*inv%mod;
    	    }
    	}
    	int n,val[maxm],A[21][maxm*4],f1[maxm*4],f2[maxm*4],b1[21][maxm*4],b2[21][maxm*4];
    	void solve(int l,int r,int id)
    	{
    	    if(l>=r)
    	    {
    	        A[id][0]=1,A[id][1]=val[l];
    	        return;
    	    }
    	    int mid=(l+r)>>1,len=(r-l+1);
    	    int m=1;
    	    while(m<=2*len) m<<=1;
    	    solve(l,mid,id+1);
    	    for(int i=0;i<=mid-l+1;i++) b1[id][i]=A[id+1][i],A[id+1][i]=0;
    	    solve(mid+1,r,id+1);
    	    for(int i=0;i<=r-mid;i++) b2[id][i]=A[id+1][i],A[id+1][i]=0;
    	    for(int i=0;i<=mid-l+1;i++) f1[i]=b1[id][i];
    	    for(int i=0;i<=r-mid;i++) f2[i]=b2[id][i];
    	    NTT(f1,m,1),NTT(f2,m,1);
    	    for(int i=0;i<m;i++) f1[i]=(ll)f1[i]*f2[i]%mod,f2[i]=0;
    	    NTT(f1,m,-1);
    	    for(int i=0;i<=len;i++) A[id][i]=f1[i],f1[i]=0;
    	}
    	int work(int N,vector<int> AA,int K)
    	{
    		if(!fl){for(int i=0;i<=20;i++)bin[1<<i]=i;fl=1;}
    	    n=N;for(int i=0;i<n;i++)val[i+1]=AA[i];
    	    solve(1,n,0);
    	    int res=0;
    	    for(int i=2;i<=K;++i)res=(res+A[0][i])%mod;
    	    return res;
    	}
    }
    vector<int> cxy[maxn];
    int f[maxn],F[maxn],sz[maxn],fa2[maxn],as[maxn],zp[maxn];
    bool w[maxn];
    void Dfs1(int u)
    {
    	sz[u]=w[u];df.insert(dfn[u]);if(!w[u])w[u]=-1;
    	for(int i=0,l=e2[u].size();i<l;++i)
    	{
    		int v=e2[u][i],w,g;
    		Dfs1(v);sz[u]+=sz[v];w=(dep[v]-dep[u]+mod)%mod;
    		g=((ll)sz[v]*w%mod+f[v])%mod;f[u]=(f[u]+g)%mod;cxy[u].push_back(g);
    	}
    	F[u]=f[u];
    }
    void Dfs2(int u,int ff)
    {
    	if(u==1)
    	{
    		as[u]=Poly::work((int)cxy[u].size(),cxy[u],min((int)cxy[u].size(),c));
    		for(int i=0,l=e2[u].size();i<l;++i)Dfs2(e2[u][i],u);
    		return;		
    	}
    	int w=(dep[u]-dep[ff]+mod)%mod;fa2[u]=ff;
    	int g=((ll)(k-2*sz[u]+mod)*w%mod+f[ff]-f[u]+mod)%mod;
    	f[u]=(f[u]+g)%mod;cxy[u].push_back(g);
    	as[u]=Poly::work((int)cxy[u].size(),cxy[u],min((int)cxy[u].size(),c));
    	for(int i=0,l=e2[u].size();i<l;++i)Dfs2(e2[u][i],u);
    }
    void Dfs3(int u)
    {
    	w[u]=f[u]=0;
    	for(int i=0,l=e2[u].size();i<l;++i)Dfs3(e2[u][i]);
    	e2[u].clear();cxy[u].clear();
    }
    int calc(int u)
    {
    	int res=0;
    	if(w[u]!=0)return as[u];
    	set<int>::iterator it=df.lower_bound(dfn[u]);
    	if(it==df.end())return 0;
    	int R=bck[*it],L=fa2[R];
    	if(dfn[R]>dfn[u]+siz[u]-1)return 0;
    	res=((f[L]-F[R]-(ll)sz[R]*(dep[R]-dep[L]+mod)%mod+(ll)(k-sz[R])*(dep[u]-dep[L]+mod)%mod)%mod+mod)%mod;
    	res=((ll)res*(F[R]+(ll)sz[R]*(dep[R]-dep[u]+mod)%mod))%mod;
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&D);
    	int u,v,T,q,la=0;
    	for(int i=1;i<n;++i)scanf("%d%d%d",&u,&v,&k),e1[u].push_back(ed{v,k}),e1[v].push_back(ed{u,k});
    	dep[1]=1,dfs1(1),dfs2(1,1);
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&k,&c);
    		for(int i=1;i<=k;++i)scanf("%d",&p[i]),w[p[i]]=1; 
    		sort(p+1,p+1+k,cmp);
    		st[top=1]=1;
    		for(int i=(p[1]==1)?2:1;i<=k;++i)ins(p[i]); 
    		for(;top>1;--top)e2[st[top-1]].push_back(st[top]);
    		Dfs1(1);Dfs2(1,0);
    		scanf("%d",&u);
    		for(int i=1;i<=u;++i)
    		{
    			scanf("%d",&v),v=(v+D*la-1)%n+1;
    			printf("%d\n",la=calc(v));
    		}
    		Dfs3(1);df.clear();
    	}
    }
    
    • 1

    信息

    ID
    5288
    时间
    2500ms
    内存
    250MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者