Problem solution: [GXOI / GZOI2019] old words

In fact, this topic has long been done, but suddenly found not made, then scrape it GZOI

Meaning of the questions: given $ x, y $ demand

$$\sum_{i\leq x}dep(lca(i,y))^k$$

First, let's look at a simplified version of this topic 

https://www.luogu.org/problem/P4211

求  $$\sum_{i\leq x}dep(lca(i,y))$$

Let's look at the actual meaning $ dep $ - from the point i to the root of how many points (including i).

We consider as a whole, asking for a discovery: all $ lca $ in $ y $ on the path to the root. So there are some points that a lot of depth to have $ lca $ contribution, and this contribution is equal to the number at this point below $ lca $, so we can put every $ lca $ each on the path to the root weights points are a plus. Then went to the root from $ y $ upwards, along the statistical weights is the answer.

Here, we can put all the off-line inquiries down, in accordance with the $ x $ sort, then each node will jump up all of the above points were painted, then the query time only need to find up to see how many nodes were painted there and calculate the contribution, here we only need to maintain the split tree chain on the line

Then I was very ugly code

#include <bits/stdc++.h>
using namespace std;

#define re register
#define ll long long
#define gc getchar()
inline ll read()
{
 	re ll x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const ll N=50500,mod=201314;
ll n,Q,k,h[N],cnt,qs;
struct edge{ll next,to;}e[N];

void add(ll u,ll v){e[++cnt]=(edge){h[u],v},h[u]=cnt;}
#define QXX(u) for(ll i=h[u],v;v=e[i].to,i;i=e[i].next)

ll dep[N],fa[N],son[N],siz[N],top[N],rev[N],seq[N],tot;

void dfs(ll u)
{
	siz[u]=1;
	QXX(u)
	{
		dfs(v);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])
			son[u]=v;
	}
}
void Dfs(ll u)
{
	if(son[u])
	{
		ll v=son[u];
		seq[v]=++tot;
		rev[tot]=v;
		top[v]=top[u];
		Dfs(v);
	}
	QXX(u)
	{
		if(v==son[u]) continue;
		seq[v]=++tot;
		rev[tot]=v;
		top[v]=v;
		Dfs(v);
	}
}

struct node{ll id,x,z,ans;bool w;}q[N<<1];
bool operator < (node a,node b){return a.x<b.x;}

#define ls id<<1
#define rs id<<1|1
#define mid ((l+r)>>1)

ll sum[N<<2],tag[N<<2];
void pushup(ll id){sum[id]=(sum[ls]+sum[rs])%mod;}

void pushdown(ll id,ll l,ll r)
{
	if(tag[id])
	{
		tag[ls]+=tag[id];
		tag[rs]+=tag[id];
		sum[ls]+=tag[id]*(mid-l+1);
		sum[rs]+=tag[id]*(r-mid);
		sum[ls]%=mod;
		sum[rs]%=mod;
		tag[id]=0;
	}
}

void change(ll id,ll l,ll r,ll L,ll R)
{
	if(l>=L&&r<=R)
	{
		tag[id]++;
		sum[id]+=(r-l+1);
		sum[id]%=mod;
		return;
	}
	pushdown(id,l,r);
	if(mid>=L) change(ls,l,mid,L,R);
	if(mid<R) change(rs,mid+1,r,L,R);
	pushup(id);
}

void work(ll x)
{
	while(1)
	{
		if(top[x]!=x)
			change(1,1,tot,seq[top[x]],seq[x]),x=fa[top[x]];
		else
		{
			change(1,1,tot,seq[x],seq[x]);
			x=fa[x];
		}
		if(x==0) return;
	}
}

ll query(ll id,ll l,ll r,ll L,ll R)
{
	if(l>=L&&r<=R) return sum[id]%mod;
	pushdown(id,l,r);
	ll ans=0;
	if(mid>=L) ans+=query(ls,l,mid,L,R);
	if(mid<R) ans+=query(rs,mid+1,r,L,R);
	return ans%mod;
}

ll ask(ll x)
{
	ll ans=0;
	while(1)
	{
		if(top[x]!=x)
			ans+=query(1,1,tot,seq[top[x]],seq[x]),x=fa[top[x]];
		else
		{
			ans+=query(1,1,tot,seq[x],seq[x]);
			x=fa[x];
		}
		ans%=mod;
		if(x==0) return ans;
	}
}

ll ans[N];

int main()
{
	n=read(),Q=read();
	for(ll i=2;i<=n;++i)
	{
		ll x=read()+1;
		add(x,i);
		fa[i]=x;
	}
	top[1]=1;seq[1]=++tot;
	dfs(1);Dfs(1);
	for(ll i=1;i<=Q;++i)
	{
		ll l=read(),r=read()+1,z=read()+1;
		q[++qs]=(node){i,l,z,0,0};
		q[++qs]=(node){i,r,z,0,1};
	}
	sort(q+1,qs+1+q);
	ll t=0;
	while(q[t+1].x<1) ++t;
	for(ll i=1;i<=n;++i)
	{
		work(i);
		while(q[t+1].x<=i&&t<qs)
			++t,q[t].ans=ask(q[t].z);
		if(t==qs) break;
	}
	for(ll i=1;i<=qs;++i)
	{
		if(q[i].w==0) ans[q[i].id]-=q[i].ans;
		else ans[q[i].id]+=q[i].ans;
	}
	for(ll i=1;i<=Q;++i)
		cout<<(ans[i]+mod)%mod<<endl;
	return 0;
}  

Then we return to this question, here it is more than a $ k $ th

First we look at the front of each $ 1 + $ where they come from $ dep [i] -> dep [i + 1] $ So here is actually doing difference, then we index into $ k $

$dep[i]^k->(dep[i]+1)^k$

So, we pre-out for each $ dep ^ k $ Then for each node is equivalent to a time will increase $ dep [x] ^ k- (dep [x] -1) ^ contribution of $

Then we can be transformed into, for a sequence, the value of each point is $ a * b $ where $ b $ is a constant value, but not the same for each node, each operation is made to modify the interval plus $ A $ 1 and interval queries

Then we maintain tree line more time to maintain a $ sum_b $ on it

 

#include <bits/stdc++.h>
using namespace std;

#define re register
#define ll long long
#define gc getchar()
inline ll read()
{
 	re ll x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const ll N=50050,mod=998244353;

ll n,Q,k,h[N],cnt,qs;
struct edge{ll next,to;}e[N];

void add(ll u,ll v){e[++cnt]=(edge){h[u],v},h[u]=cnt;}
#define QXX(u) for(ll i=h[u],v;v=e[i].to,i;i=e[i].next)

ll dep[N],fa[N],son[N],siz[N],top[N],seq[N],rev[N],tot;

void dfs(ll u)
{
	siz[u]=1;
	QXX(u)
	{
		dep[v]=dep[u]+1;
		dfs(v);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])
			son[u]=v;
	}
}
void Dfs(ll u,ll to)
{
	seq[u]=++tot,rev[tot]=u;
	top[u]=to;
	if(son[u])
		Dfs(son[u],top[u]);
	QXX(u)
	{
		if(v==son[u]) continue;
		Dfs(v,v);
	}
}

ll qpow(ll x,ll b)
{
	ll a=1;
	while(b)
	{
		if(b&1) a=(x*a)%mod;
		x=(x*x)%mod,b>>=1;
	}
	return a;
}

#define ls id<<1
#define rs id<<1|1
#define mid ((l+r)>>1)

ll su[N<<2],sum[N<<2],tag[N<<2],po[N];

void pushup(ll id)
{
	sum[id]=sum[ls]+sum[rs];
	su[id]=su[ls]+su[rs];
}
void pushdown(ll id,ll l,ll r)
{
	if(tag[id])
	{
		tag[ls]+=tag[id];
		tag[rs]+=tag[id];
		sum[ls]=(sum[ls]+tag[id]*su[ls])%mod;
		sum[rs]=(sum[rs]+tag[id]*su[rs])%mod;
		tag[id]=0;
	}
}
void built(ll id,ll l,ll r)
{
	if(l==r)
	{
		su[id]=(po[dep[rev[l]]]+mod-po[dep[rev[l]]-1])%mod;
		return;
	}
	built(ls,l,mid);
	built(rs,mid+1,r);
	pushup(id);
}
void change(ll id,ll l,ll r,ll L,ll R)
{
	if(l>=L&&r<=R)
	{
		tag[id]++;
		sum[id]+=su[id];
		sum[id]%=mod;
		return;
	}
	pushdown(id,l,r);
	if(mid>=L) change(ls,l,mid,L,R);
	if(mid<R) change(rs,mid+1,r,L,R);
	pushup(id);
}
ll query(ll id,ll l,ll r,ll L,ll R)
{
	if(l>=L&&r<=R) return sum[id]%mod;
	pushdown(id,l,r);
	ll ans=0;
	if(mid>=L) ans+=query(ls,l,mid,L,R);
	if(mid<R) ans+=query(rs,mid+1,r,L,R);
	return ans%mod;
}
void work(ll x)
{
	while(1)
	{
		if(top[x]!=x)
			change(1,1,tot,seq[top[x]],seq[x]),x=fa[top[x]];
		else
		{
			change(1,1,tot,seq[x],seq[x]);
			x=fa[x];
		}
		if(x==0) return;
	}
}
ll ask(ll x)
{
	ll ans=0;
	while(1)
	{
		if(top[x]!=x)
			ans+=query(1,1,tot,seq[top[x]],seq[x]),x=fa[top[x]];
		else
		{
			ans+=query(1,1,tot,seq[x],seq[x]);
			x=fa[x];
		}
		ans%=mod;
		if(x==0) return ans;
	}
}
struct node{ll id,x,y,ans;}q[N];
bool cmpx(node a,node b){return a.x<b.x;}
bool cmpi(node a,node b){return a.id<b.id;}

int main()
{
	n=read(),Q=read(),k=read();
	for(ll i=1;i<=n;++i)
		po[i]=qpow(i,k);
	for(ll i=2;i<=n;++i)
	{
		fa[i]=read();
		add(fa[i],i);
	}
	dep[1]=1;
	dfs(1),Dfs(1,1);
	built(1,1,tot);
	for(ll i=1;i<=Q;++i)
	{
		ll x=read(),y=read();
		q[i]=(node){i,x,y,0};
	}
	sort(q+1,q+1+Q,cmpx);
	ll t=0;
	while(q[t+1].x<1) ++t;
	for(ll i=1;i<=n;++i)
	{
		work(i);
		while(q[t+1].x<=i&&t<Q)
			++t,q[t].ans=ask(q[t].y);
		if(t==Q) break;
	}
	sort(q+1,q+1+Q,cmpi);
	for(ll i=1;i<=Q;++i)
		cout<<q[i].ans<<endl;
	return 0;
}

  

 

Guess you like

Origin www.cnblogs.com/zijinjun/p/11256866.html