• [GXOI/GZOI2019]旧词


    Description

    给定一棵 (n) 个点的有根树,节点标号 (1 sim n)(1) 号节点为根。

    给定常数 (k)
    给定 (Q) 个询问,每次询问给定 (x,y)

    求:

    [sumlimits_{i le x} ext{depth}( ext{lca}(i,y))^k ]

    ( ext{lca}(x,y)) 表示节点 (x) 与节点 (y) 在有根树上的最近公共祖先。
    ( ext{depth}(x)) 表示节点 (x) 的深度,根节点的深度为 (1)
    由于答案可能很大,你只需要输出答案模 (998244353) 的结果。

    Solution

    (k=1) 的时候就是 [LNOI2014]LCA.

    (k ot =1) 的时候其实本质上是一样的,我们需要保证加入一个节点 (x) 的对 (y) 的贡献为 (depth(lca(x,y))^k) ,那么我们可以构造一个序列,把 (x) 到根路径上全部加上这段序列后查询 y 到根的路径和会新增 (depth(lca(x,y))^k),所以令这个序列为 (A),则 (A_i=dep(i)^k-dep(i-1)^k),由于路径深度是连续的,所以巧妙地差分掉了,其余的做法和上面那道题相似,不再赘述。

    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <fstream>
    
    using namespace std;
    
    #define LL long long
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define MP(x, y) std::make_pair(x, y)
    #define DE(x) cout << #x << " = " << x << endl
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define GO cerr << "GO" << endl;
    
    inline void proc_status()
    {
    	ifstream t("/proc/self/status");
    	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
    }
    template<class T> inline T read() 
    {
    	register char c;
    	register T x(0), f(1);
    	while (!isdigit(c = getchar())) if (c == '-') f = -1;
    	while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    	return x * f;
    }
    template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
    
    const int maxN=5e4;
    
    #define mod (998244353)
    inline void Mod(int& x) { x>=mod?x-=mod:0;}
    
    LL qpow(LL a,LL b)
    {
    	LL ans(1);
    	while(b)
    	{
    		if(b&1)ans=ans*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return ans;
    }
    
    int n,Q,k;
    int ver[maxN<<1],nxt[maxN<<1],head[maxN+2],tot;
    int A[maxN+2],dfn[maxN+2],son[maxN+2],size[maxN+2],dep[maxN+2],rev[maxN+2],dfst,top[maxN+2],fa[maxN+2];
    int sum[maxN<<2],tag[maxN<<2];
    void link(int u,int v)
    {
    	ver[++tot]=v,nxt[tot]=head[u],head[u]=tot;
    }
    void DFS1(int u,int f)
    {
    	fa[u]=f;
    	dep[u]=dep[f]+1;
    	size[u]=1;
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=ver[i];
    		if(v==f)continue;
    		DFS1(v,u);
    		size[u]+=size[v];
    		if(size[son[u]]<size[v])son[u]=v;
    	}
    }
    void DFS2(int u,int topf)
    {
    	dfn[u]=++dfst;
    	rev[dfst]=u;
    	top[u]=topf;
    	if(son[u])DFS2(son[u],topf);
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=ver[i];
    		if(v==son[u]||v==fa[u])continue;
    		DFS2(v,v);
    	}
    }
    void init()
    {
    	DFS1(1,0);
    	DFS2(1,1);
    	for(int i=1;i<=n;++i)
    		A[i]=(A[i-1]+qpow(dep[rev[i]],k)-qpow(dep[rev[i]]-1,k)+mod)%mod;
    }
    void push(int x,int v,int l,int r)
    {
    	tag[x]+=v;
    	sum[x]+=(LL)(A[r]-A[l-1]+mod)*v%mod;
    	Mod(sum[x]);
    }
    void pushdown(int x,int l,int r)
    {
    	if(tag[x])
    	{
    		int mid((l+r)>>1);
    		push(x<<1,tag[x],l,mid);
    		push(x<<1|1,tag[x],mid+1,r);
    		tag[x]=0;
    	}
    }
    void add(int x,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R)
    		return push(x,1,l,r);
    	int mid=(l+r)>>1;
    	pushdown(x,l,r);
    	if(L<=mid)add(x<<1,l,mid,L,R);
    	if(mid<R)add(x<<1|1,mid+1,r,L,R);
    	sum[x]=sum[x<<1]+sum[x<<1|1],Mod(sum[x]);
    }
    int query(int x,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R)
    		return sum[x];
    	int mid=(l+r)>>1;
    	pushdown(x,l,r);
    	int ans(0);
    	if(L<=mid)ans+=query(x<<1,l,mid,L,R);
    	if(mid<R)ans+=query(x<<1|1,mid+1,r,L,R),Mod(ans);
    	return ans;
    }
    vector<pair<int, int> >q[maxN+2];
    int ans[maxN+2];
    int main() 
    {
    #ifndef ONLINE_JUDGE
    	freopen("xhc.in", "r", stdin);
    	freopen("xhc.out", "w", stdout);
    #endif
    	n=read<int>(),Q=read<int>(),k=read<int>();
    	for(int i=2;i<=n;++i)
    	{
    		int f(read<int>());
    		link(f,i);
    		link(i,f);
    	}
    	init();
    	for(int i=1;i<=Q;++i)
    	{
    		int x(read<int>()),y(read<int>());
    		q[x].push_back(MP(y,i));
    	}
    	for(int i=1;i<=n;++i)
    	{
    		int u=i;
    		while(u)
    		{
    			add(1,1,n,dfn[top[u]],dfn[u]);
    			u=fa[top[u]];
    		}
    		for(int j=0;j<SZ(q[i]);++j)
    		{
    			int u=q[i][j].first,id=q[i][j].second,res=0;
    			while(u)
    			{
    				res+=query(1,1,n,dfn[top[u]],dfn[u]);
    				Mod(res);
    				u=fa[top[u]];
    			}
    			ans[id]=res;
    		}
    	}
    	for(int i=1;i<=Q;++i)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    浅析CSS shapes布局及了解shapeoutside属性及其应用
    浅析模块化的演进发展历史、模块化标准规范的建立历史及深入理解模块打包工具webpack究竟解决什么问题
    浅析前端如何做单元测试:jest与mocha对比、如何使用jest进行单元测试及持续监听、如何生成测试覆盖率报告、常用断言方法、如何测试异步函数
    Asp.Net Core 缓存使用_Asp.Net core 浏览器缓存(客户端缓存)
    Asp.Net Core 缓存使用_Asp.Net core 服务器缓存IMemoryCache(服务器缓存)
    关于 Span 的一切:探索新的 .NET 明星: 2. Span<T> 是如何实现的?
    关于 Span 的一切:探索新的 .NET 明星: 1 Span<T> 是什么?
    翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6
    CoreWCF 1.0 正式发布,支持 .NET Core 和 .NET 5+ 的 WCF
    【转】PV,VG,LV的关系和操作
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/11567668.html
Copyright © 2020-2023  润新知