P5305 [GXOI/GZOI2019] 旧词

观前提醒:这并不是本题的一般解法,但是思路过于抽象,而且卡常卡了好几天,故专门记录一下

题目传送门

注意到数据范围是 \(n,q \le 5e4\),考虑莫队(事实上本题的弱化版也是莫队)

\(x\) 是容易转移的,加上/减去变化的点与目前询问的点的 \(lca\) 产生的贡献即可, \(DFS\) 序求 \(lca\) 可以做到 \(O(1)\) 转移

考虑树上从一个点 \(u\) 到与之相邻的另一个点 \(v\) :(不妨设 \(dep_u<dep_v\)

转移前后,\(u\) 子树以外的点的 \(lca\) 并没有变化, \(u\) 子树内 \(v\) 子树外的点的 \(lca\) 也没有变化(还是 \(u\) ),只有 \(v\) 子树以内的点的 \(lca\) 会从 \(u\) 变成 \(v\) ,并改变相应的贡献

那就好说了,转移时查询 \(v\) 子树内编号 \(\le x\) 的点的数量就行了,树剖+主席树即可

\(dep_u>dep_v\)同理

跑一个块复杂度 \(O(2nlogn)\)

如果以 \(x\) 分块,块长为 \(len\),总复杂度 \(O(2n^2logn/len+nlen)\),实测 \(len\)\(1700\) 时可过(最慢的点 \(705ms\)

代码:

#include<bits/stdc++.h>
#define rint register int
#define ll long long
using namespace std;

const int BUFSIZE = 1<<20;
char ibuf[BUFSIZE],*is=ibuf,*it=ibuf;
inline char getch()
{
	if(is==it)
		it=(is=ibuf)+fread(ibuf,1,BUFSIZE,stdin);
	return is==it?EOF:*is++;
}
inline int read(){
	int res=0,neg=0,ch=getch();
	while(!(isdigit(ch) or ch == '-') and ch != EOF)
		ch=getch();
	if(ch=='-')
		neg=1, ch=getch();
	while(isdigit(ch))
		res=res*10+(ch-'0'),ch=getch();
	return neg?-res:res;
}
void write(int x)
{
	if(x<0)	x=-x,putchar('-');
	if(x<10){putchar(x+'0');return;}
	write(x/10ll);putchar(x%10ll+'0');
}

const int N=5e4+10,mod=998244353;
int n,q,k;
vector<int>ed[N];

ll qmi(ll a,int b)
{
	ll res=1;
	while(b)
	{
		if(b&1)	res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

int len;
int in[N];
ll pre[N];
struct seg
{
	int lson,rson;
	int data;
}tr[N<<5];
int tot;
int root[N];
int build(int l,int r)
{
	++tot;
	if(l==r)	return tot;
	int mid=l+r>>1;
	tr[tot].lson=build(l,mid),tr[tot].rson=build(mid+1,r);
	return tot;
}
int upd(int lst,int l,int r,int k)
{
	int p=++tot;
	if(l==r)
	{
		tr[p].data++;
		return p;
	}
	tr[p].data=tr[lst].data;
	int mid=l+r>>1;
	if(k<=mid)	tr[p].lson=upd(tr[lst].lson,l,mid,k),tr[p].rson=tr[lst].rson;
	else	tr[p].lson=tr[lst].lson,tr[p].rson=upd(tr[lst].rson,mid+1,r,k);
	tr[p].data=tr[tr[p].lson].data+tr[tr[p].rson].data;
	return p;
}
int query(int p1,int p2,int l,int r,int k)
{
	if(k>=r)	return tr[p1].data-tr[p2].data;
	int mid=l+r>>1,res=0;
	res+=query(tr[p1].lson,tr[p2].lson,l,mid,k);
	if(k>mid)	res+=query(tr[p1].rson,tr[p2].rson,mid+1,r,k);
	return res;
}

int dep[N],siz[N];
int fa[N];
int eul[N<<1],vis[N<<1],tote,dfn[N],num,rk[N];
int st[N<<1][21];
void dfs(int u,int fath)
{
	siz[u]=1;
	fa[u]=fath;
	dep[u]=dep[fath]+1;
	dfn[u]=++num;
	rk[num]=u;
	
	eul[++tote]=u,st[tote][0]=u;
	if(!vis[u])	vis[u]=tote;
	for(int v:ed[u])
	{
		dfs(v,u);
		eul[++tote]=u,st[tote][0]=u;
		siz[u]+=siz[v];
	}
}
void init()
{
	for(int j=1;j<19;j++)
		for(int i=1;i+(1<<j-1)<=tote;i++)
		{
			int x=st[i][j-1],y=st[i+(1<<j-1)][j-1];
			if(dep[x]<dep[y])	st[i][j]=x;
			else st[i][j]=y;
		}
}
int lca(int x,int y)
{
	if(x>y)	swap(x,y);
	int j=__lg(y-x+1);
	int l=st[x][j],r=st[y-(1<<j)+1][j];
	if(dep[l]<dep[r])	return l;
	else	return r;
}

struct node
{
	int x,y,id;
	bool operator <(const node &a)const
	{
		if(in[x]==in[a.x])
		{
			if(in[x]&1)	return dfn[y]<dfn[a.y];
			else	return dfn[y]>dfn[a.y];
		}
		return in[x]<in[a.x];
	}
}ask[N];

ll res;
ll ans[N];
int x;
void modify(int u,int v,int op)
{
	int sum=query(root[dfn[v]+siz[v]-1],root[dfn[v]-1],1,n,x);
	res=((res+sum*(pre[dep[v]]-pre[dep[u]]+mod)*op)%mod+mod)%mod;
}

void modify(int u,int v)
{
	int anc=lca(vis[u],vis[v]);
	while(u!=anc)
	{
		modify(fa[u],u,-1);
		u=fa[u];
	}
	while(u!=v)
	{
		modify(fa[v],v,1);
		v=fa[v];
	}
}

signed main()
{
	n=read(),q=read(),k=read();
	pre[0]=1;
	for(rint i=1;i<=n;i++)	pre[i]=qmi(i,k)%mod;
	len=1700;
	for(rint i=1;i<=n;i++)	in[i]=(i/len)+1;
	for(rint i=2;i<=n;i++)
	{
		int u=read();
		ed[u].push_back(i);
	}
	dfs(1,0);
	init();
	
	root[0]=build(1,n);
	for(rint i=1;i<=n;i++)
		root[i]=upd(root[i-1],1,n,rk[i]);
	
	for(rint i=1;i<=q;i++)	ask[i].x=read(),ask[i].y=read(),ask[i].id=i;
	sort(ask+1,ask+q+1);
	x=0;
	int u=1;
	for(rint i=1;i<=q;i++)
	{
		while(x<ask[i].x)	res=(res+pre[dep[lca(vis[++x],vis[u])]])%mod;
		while(x>ask[i].x)	res=(res-pre[dep[lca(vis[x--],vis[u])]]+mod)%mod;
		while(dfn[u]<dfn[ask[i].y])
		{
			modify(u,rk[dfn[u]+1]);
			u=rk[dfn[u]+1];
		}
		while(dfn[u]>dfn[ask[i].y])
		{
			modify(u,rk[dfn[u]-1]);
			u=rk[dfn[u]-1];
		}
		ans[ask[i].id]=res;
	}
	for(rint i=1;i<=q;i++)	write(ans[i]),puts("");
	return 0;
}
posted @ 2025-05-20 19:55  zlc1082  阅读(61)  评论(2)    收藏  举报