【GMOJ4488】疯狂动物城

题目

题目链接:https://gmoj.net/senior/#main/show/4488

思路

其实思路并不难,就是一道码农题罢了 /fad。
对于一次询问 \(x,y\),我们设 \(\operatorname{lca}(x,y)=p\),我们把从 \(x\)\(y\) 的道路拆成 \(x\to p\)\(p\to y\) 两条(注意 \(p\) 被计算了两次,最后要减去一次 \(p\) 的贡献),然后分类讨论:

  • 对于 \(x\to p\) 的点 \(k\),它到 \(y\) 的距离就是 \(dep[k]+dep[y]-2dep[p]\),设 \(t=dep[y]-2dep[p]\),那么它的贡献就是

\[\frac{a_k(dep[k]+t)(dep[k]+t+1)}{2} \]

化简得

\[\frac{a_kdep[k]^2+a_kdep[k](2t+1)+a_k(t^2+t)}{2} \]

  • 对于 \(p\to y\) 的点 \(k\),它到 \(y\) 的距离就是 \(dep[y]-dep[k]\),设 \(t=dep[y]\),那么它的贡献就是

\[\frac{a_k(t-dep[x])(t-dep[x]+1)}{2} \]

化简得

\[\frac{a_kdep[k]^2-a_kdep[k](2t+1)+a_k(t^2+t)}{2} \]

我们发现,只需要在树上维护链 \(\sum a_k,\sum a_kdep[k],\sum a_kdep[k]^2\) 这三个信息,询问时乘上 \(t\) 即可。
为了方便,我们可以将所有信息乘上 \(2\),然后在输出的时候再将答案乘上 \(2\)\(\bmod 20160501\) 时的逆元。通过计算可得到 \(\frac{1}{2}\equiv 10080251\pmod {20160501}\)
然后就是树剖上主席树维护上面三个信息了。
区间修改时,我们要先预处理出 \(sumd[i][1/2]\) 表示在树剖之后,编号为 \(1\sim i\) 的点的深度的一次方 / 二次方和,然后区间修改就可以直接用 \(delta\) 乘上区间 \(sumd\)
细节其实挺多的,写题时思路还是要清晰些。
然后由于我是菜鸡,求 \(\operatorname{LCA}\) 习惯性写了倍增 23333。

代码

// QuantAsk YYDS!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=100010,LG=17,MOD=20160501,MAXN=N*LG*4,inv2=10080251;
int a[N],head[N],rt[N],dep[N],son[N],size[N],id[N],rk[N],top[N],f[N][LG+1],sumd[N][3];
int now,n,m,Q,tot,last,opt,X,Y,V;

struct edge
{
	int next,to;
}e[N*2];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void dfs1(int x,int fa)
{
	f[x][0]=fa; dep[x]=dep[fa]+1; size[x]=1;
	for (int i=1;i<=LG;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa)
		{
			dfs1(v,x);
			size[x]+=size[v];
			if (size[v]>size[son[x]]) son[x]=v;
		}
	}
}

void dfs2(int x,int tp)
{
	top[x]=tp; id[x]=++tot; rk[tot]=x;
	if (son[x]) dfs2(son[x],tp);
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=f[x][0] && v!=son[x]) dfs2(v,v);
	}
}

int lca(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=LG;i>=0;i--)
		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
	if (x==y) return x;
	for (int i=LG;i>=0;i--)
		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}

struct SegTree
{
	int tot,lc[MAXN],rc[MAXN],lazy[MAXN],sum[MAXN][3];
	
	int New(int now)
	{
		int x=++tot;
		lc[x]=lc[now]; rc[x]=rc[now]; lazy[x]=lazy[now];
		sum[x][0]=sum[now][0]; sum[x][1]=sum[now][1]; sum[x][2]=sum[now][2];
		return x;
	}
	
	void pushup(int x)
	{
		sum[x][0]=(sum[lc[x]][0]+sum[rc[x]][0])%MOD;
		sum[x][1]=(sum[lc[x]][1]+sum[rc[x]][1])%MOD;
		sum[x][2]=(sum[lc[x]][2]+sum[rc[x]][2])%MOD;
	}
	
	void pushdown(int now,int x,int l,int r)
	{
		if (lazy[x])
		{
			int mid=(l+r)>>1;
			if (!lc[x] || lc[x]<x) lc[x]=New(lc[now]);
			if (!rc[x] || rc[x]<x) rc[x]=New(rc[now]);
			if (lc[x])
			{
				sum[lc[x]][0]=(sum[lc[x]][0]+1LL*lazy[x]*(mid-l+1))%MOD;
				sum[lc[x]][1]=(sum[lc[x]][1]+1LL*lazy[x]*(sumd[mid][1]-sumd[l-1][1]))%MOD;
				sum[lc[x]][2]=(sum[lc[x]][2]+1LL*lazy[x]*(sumd[mid][2]-sumd[l-1][2]))%MOD;
				lazy[lc[x]]=(lazy[lc[x]]+lazy[x])%MOD;
			}
			if (rc[x])
			{
				sum[rc[x]][0]=(sum[rc[x]][0]+1LL*lazy[x]*(r-mid))%MOD;
				sum[rc[x]][1]=(sum[rc[x]][1]+1LL*lazy[x]*(sumd[r][1]-sumd[mid][1]))%MOD;
				sum[rc[x]][2]=(sum[rc[x]][2]+1LL*lazy[x]*(sumd[r][2]-sumd[mid][2]))%MOD;
				lazy[rc[x]]=(lazy[rc[x]]+lazy[x])%MOD;
			}
			lazy[x]=0;
		}
	}
	
	int build(int l,int r)
	{
		int x=++tot;
		if (l==r)
		{
			sum[x][0]=a[rk[l]];
			sum[x][1]=1LL*a[rk[l]]*dep[rk[l]]%MOD;
			sum[x][2]=1LL*a[rk[l]]*dep[rk[l]]%MOD*dep[rk[l]]%MOD;
			return x;
		}
		int mid=(l+r)>>1;
		lc[x]=build(l,mid); rc[x]=build(mid+1,r);
		pushup(x);
		return x;
	}
	
	int update(int now,int x,int l,int r,int ql,int qr,ll v)
	{
		if (!x || x==now) x=New(now);
		if (l==ql && r==qr)
		{
			sum[x][0]=(sum[x][0]+v*(r-l+1))%MOD;
			sum[x][1]=(sum[x][1]+v*(sumd[r][1]-sumd[l-1][1]))%MOD;
			sum[x][2]=(sum[x][2]+v*(sumd[r][2]-sumd[l-1][2]))%MOD;
			lazy[x]=(lazy[x]+v)%MOD;
			return x;
		}
		pushdown(now,x,l,r);
		int mid=(l+r)>>1;
		if (qr<=mid) lc[x]=update(lc[now],lc[x],l,mid,ql,qr,v);
		else if (ql>mid) rc[x]=update(rc[now],rc[x],mid+1,r,ql,qr,v);
		else lc[x]=update(lc[now],lc[x],l,mid,ql,mid,v),rc[x]=update(rc[now],rc[x],mid+1,r,mid+1,qr,v);
		pushup(x);
		return x;
	}
	
	ll query(int x,int l,int r,int ql,int qr,ll t,bool ff)
	{
		if (l==ql && r==qr)
			if (ff) return (1LL*sum[x][0]*(t*t%MOD+t)+1LL*sum[x][1]*(t*2+1)+sum[x][2])%MOD;
			else return (1LL*sum[x][0]*(t*t%MOD+t)-1LL*sum[x][1]*(t*2+1)+sum[x][2])%MOD;
		pushdown(x,x,l,r);
		int mid=(l+r)>>1;
		if (qr<=mid) return query(lc[x],l,mid,ql,qr,t,ff);
		if (ql>mid) return query(rc[x],mid+1,r,ql,qr,t,ff);
		return (query(lc[x],l,mid,ql,mid,t,ff)+query(rc[x],mid+1,r,mid+1,qr,t,ff))%MOD;
	}
}seg;

void Update(int x,int y)
{
	while (dep[top[x]]>dep[y])
	{
		rt[m]=seg.update(rt[now],rt[m],1,n,id[top[x]],id[x],V);
		x=f[top[x]][0];
	}
	rt[m]=seg.update(rt[now],rt[m],1,n,id[y],id[x],V);
}

ll Query(int x,int y,ll t,bool ff)
{
	ll s=0;
	while (dep[top[x]]>dep[y])
	{
		s=(s+seg.query(rt[now],1,n,id[top[x]],id[x],t,ff))%MOD;
		x=f[top[x]][0];
	}
	return (s+seg.query(rt[now],1,n,id[y],id[x],t,ff))%MOD;
}

int main()
{
	freopen("zootopia.in","r",stdin);
	freopen("zootopia.out","w",stdout);	
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&Q);
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	tot=now=0;
	dfs1(1,0); dfs2(1,1);
	for (int i=1;i<=n;i++)
	{
		sumd[i][1]=(sumd[i-1][1]+dep[rk[i]])%MOD;
		sumd[i][2]=(sumd[i-1][2]+1LL*dep[rk[i]]*dep[rk[i]])%MOD;
	}
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	rt[0]=seg.build(1,n);	
	while (Q--)
	{
		scanf("%d",&opt);
		if (opt==1)
		{
			scanf("%d%d%d",&X,&Y,&V);
			X^=last; Y^=last;
			int p=lca(X,Y);
			rt[++m]=0;
			Update(X,p); Update(Y,p);
			rt[m]=seg.update(rt[now],rt[m],1,n,id[p],id[p],-V);
			now=m;
		}
		if (opt==2)
		{
			scanf("%d%d",&X,&Y);
			X^=last; Y^=last;
			int p=lca(X,Y);
			last=(Query(X,p,dep[Y]-2LL*dep[p],1)+Query(Y,p,dep[Y],0)-seg.query(rt[now],1,n,id[p],id[p],dep[Y],0))*inv2%MOD;
			last=(last+MOD)%MOD;
			printf("%d\n",last);
		}
		if (opt==3) 
		{
			scanf("%d",&now);
			now^=last;
		}
	}
	return 0;
}
posted @ 2020-10-29 08:19  stoorz  阅读(115)  评论(0编辑  收藏  举报