Luogu P5305 [GXOI/GZOI2019]旧词

好套路的题目,和Luogu P4211 [LNOI2014]LCA基本上就是一个题

先考虑\(\sum{i\le x} \operatorname{depth(\operatorname{lca}(i,y))}\)怎么做(其实就是LNOI那题)

很容易发现此时我们两个点对的贡献为\(\operatorname{lca}\)的深度\(\Leftrightarrow\)两点与根节点公共路径长度

所以我们可以利用莫队+树剖,每次加一个点就是到根的一条链加\(1\),查询就是查某个点到根的路径和,复杂度是\(O(n\sqrt n\log^2 n)\)

然后发现删除其实完全没有必要,因此我们离线一下就变成\(O(n\log^2 n)\)的了

那么考虑这题怎么做,上面的算法相当于这里的\(k=1\),而这个累加的\(1\)其实就是\(( \operatorname{depth}(x)+1)^1-\operatorname{depth}(x)^1\),是一个树上差分的过程

因此这题每个点每次要加上的值就是\(( \operatorname{depth}(x)+1)^k-\operatorname{depth}(x)^k\),乍一看不好维护,其实仔细想一想每次加的都是定值

那么我们线段树处理出所有对应区间的每次增加值的和,修改的时候加上这个值即可。总体复杂度\(O(n\log^2 n)\)

CODE

#include<cstdio>
#include<cctype>
#include<vector>
#include<utility>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
typedef pair <int,int> pi;
const int N=50005,mod=998244353;
struct edge
{
	int to,nxt;
}e[N]; int head[N],n,q,k,cnt,anc[N],dep[N],id[N],s[N],x,y,ans[N]; vector <pi> et[N];
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
		char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
	public:
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x)
		{
			if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
			while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
		}
		inline void Fend(void)
		{
			fwrite(Fout,1,Ftop,stdout);
		}
		#undef tc
		#undef pc
}F;
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline int sum(CI a,CI b)
{
	int t=a+b; return t>=mod?t-mod:t;
}
inline int sub(CI a,CI b)
{
	int t=a-b; return t<0?t+mod:t;
}
inline int quick_pow(int x,int p,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void addedge(CI x,CI y)
{
	e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
}
class Segment_Tree
{
	private:
		struct segment
		{
			int sum,val,tag;
		}node[N<<2];
		#define ls now<<1
		#define rs now<<1|1
		#define S(x) node[x].sum
		#define V(x) node[x].val
		#define T(x) node[x].tag
		inline void pushdown(CI now)
		{
			if (!T(now)) return; T(ls)+=T(now); inc(S(ls),1LL*T(now)*V(ls)%mod);
			T(rs)+=T(now); inc(S(rs),1LL*T(now)*V(rs)%mod); T(now)=0;
		}
	public:
		#define TN CI now=1,CI l=1,CI r=n
		#define LS ls,l,mid
		#define RS rs,mid+1,r
		inline void build(TN)
		{
			if (l==r) return (void)(V(now)=sub(quick_pow(dep[s[l]]+1,k),quick_pow(dep[s[l]],k)));
			int mid=l+r>>1; build(LS); build(RS); V(now)=sum(V(ls),V(rs));
		}
		inline int query(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return S(now); int mid=l+r>>1,ret=0; pushdown(now);
			if (beg<=mid) inc(ret,query(beg,end,LS)); if (end>mid) inc(ret,query(beg,end,RS)); return ret;
		}
		inline void modify(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return ++T(now),inc(S(now),V(now)); int mid=l+r>>1; pushdown(now);
			if (beg<=mid) modify(beg,end,LS); if (end>mid) modify(beg,end,RS); S(now)=sum(S(ls),S(rs));
		}
		#undef ls
		#undef rs
		#undef S
		#undef V
		#undef T
		#undef TN
		#undef LS
		#undef RS
}SEG;
class Heavy_Light_Division
{
	private:
		int son[N],top[N],size[N],idx;
	public:
		#define to e[i].to
		inline void DFS1(CI now)
		{
			size[now]=1; for (RI i=head[now];i;i=e[i].nxt)
			{
				dep[to]=dep[now]+1; DFS1(to); size[now]+=size[to];
				if (size[to]>size[son[now]]) son[now]=to;
			}
		}
		inline void DFS2(CI now,CI topf=1)
		{
			s[id[now]=++idx]=now; top[now]=topf; if (son[now]) DFS2(son[now],topf);
			for (RI i=head[now];i;i=e[i].nxt) if (to!=son[now]) DFS2(to,to);
		}
		inline int query(int nw,int ret=0)
		{
			while (top[nw]) inc(ret,SEG.query(id[top[nw]],id[nw])),nw=anc[top[nw]]; return ret;
		}
		inline void modify(int nw)
		{
			while (top[nw]) SEG.modify(id[top[nw]],id[nw]),nw=anc[top[nw]];
		}
		#undef to
}T;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (F.read(n),F.read(q),F.read(k),i=2;i<=n;++i)
	F.read(anc[i]),addedge(anc[i],i); for (i=1;i<=q;++i)
	F.read(x),F.read(y),et[x].push_back(make_pair(y,i));
	for (T.DFS1(1),T.DFS2(1),SEG.build(),i=1;i<=n;++i)
	{
		T.modify(i); for (pi it:et[i]) ans[it.second]=T.query(it.first);
	}
	for (i=1;i<=q;++i) F.write(ans[i]); return F.Fend(),0;
}
posted @ 2019-06-03 13:15  空気力学の詩  阅读(173)  评论(0编辑  收藏  举报