雅礼集训

[雅礼集训Day1]

真•神仙打架,考出来9分,暴力打炸?!总结一下第一题。
一道经典的支持换根的树链剖分,需要支持的操作有:
1.将根设为root.
2.设u, v的最近公共祖先为p, 将p的子树中的所有点的权值加上x.
3.查询u的子树中的所有点的权值和.
对于这一类题目,其实我们并不需要真正去换根,我们只需要记录一下当前的根是谁,然后在更改和查询的时候修改一下即可。
这道题真正的难点在于如何确定lca
题解:
经过一些简单的讨论可以知道,\(u\)\(v\)在以\(root\)为根时的\(lca\)为:\(lca(u, v)\),\(lca(u, root)\),\(lca(v, root)\)中原来深度最大的一个,其中\(lca(a, b)\)代表\(a\),\(b\)在以\(1\)为根时的\(lca\)
太菜了并不会证,所以记一下结论吧
确定了\(lca\)之后就好做了,对于查询操作,判断当前\(root\)是否在\(u\)的子树中,
如果不在,直接查询原来的子树
如果在,运用dfs序的连续性排除\(root\)所在儿子的子树,查询其他即可。画图模拟一下很好看出来。
注意特判\(u\)是否是\(root\)因为这个调了好久

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#define debug cout<<"....."<<endl;
#define lll long long
#define ll(x) (x*2)
#define rr(x) (x*2+1)
using namespace std;
lll read()
{
	lll x=0,w=1;char ch=getchar();
	while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*w;
}
lll n,q,cnt,m,opt,x,y,z,node;
lll head[300010],deep[300010],a[300010],size[300010],s[300010],pos[3000010];
lll sgm[1200010],lazy[1200010];
lll f[300010][21];
struct node{
	lll to,next;
}edge[600010];
void add(lll x,lll y)
{
	cnt++;edge[cnt].to=y;edge[cnt].next=head[x];head[x]=cnt;
}
void init()
{
	for(lll i=1;i<=20;i++)
		for(lll j=1;j<=n;j++)
			f[j][i]=f[f[j][i-1]][i-1];
}
void dfs(lll k,lll fa)
{
	lll v;
	s[++m]=k;pos[k]=m;
	for(lll i=head[k];i;i=edge[i].next)
	{
		v=edge[i].to;
		if(v==fa) continue;
		deep[v]=deep[k]+1;f[v][0]=k;
		dfs(v,k);
		size[k]+=size[v];
	}
	size[k]++;
}
lll LCA(lll x,lll y)
{
	if(deep[x]<deep[y]) swap(x,y);
	for(lll i=20;i>=0;i--)
		if(deep[f[x][i]]>=deep[y]) x=f[x][i];
	if(x==y) return x;
	for(lll i=20;i>=0;i--)
		if(f[x][i]!=f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}
void push_down(lll root,lll l,lll r)
{
	lll mid=(l+r)/2;
	if(!lazy[root]) return;
	sgm[ll(root)]+=(mid-l+1)*lazy[root];sgm[rr(root)]+=(r-mid)*lazy[root];
	lazy[ll(root)]+=lazy[root];lazy[rr(root)]+=lazy[root];lazy[root]=0;
	return;
}
void build(lll root,lll l,lll r)
{
	if(l>r) return;
	if(l==r)
	{
		sgm[root]=a[s[l]];
		return;
	}
	lll mid=(l+r)/2;
	if(l<=mid) build(ll(root),l,mid);
	if(r>mid) build(rr(root),mid+1,r);
	sgm[root]=sgm[ll(root)]+sgm[rr(root)];
}
void insert(lll root,lll l,lll r,lll left,lll right,lll v)
{
	if(l>r) return;
	if(l>right||r<left) return;
	if(left<=l&&r<=right)
	{
		sgm[root]+=(r-l+1)*v;lazy[root]+=v;
		return;
	}
	lll mid=(l+r)/2;
	push_down(root,l,r);
	if(l<=mid) insert(ll(root),l,mid,left,right,v);
	if(r>mid) insert(rr(root),mid+1,r,left,right,v);
	sgm[root]=sgm[ll(root)]+sgm[rr(root)];
}
lll query(lll root,lll l,lll r,lll left,lll right)
{
	if(l>r) return 0;
	if(l>right||r<left) return 0;
	if(left<=l&&r<=right) return sgm[root];
	lll mid=(l+r)/2;
	push_down(root,l,r);
	return query(ll(root),l,mid,left,right)+query(rr(root),mid+1,r,left,right);
}
int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read();q=read();node=1;
	for(lll i=1;i<=n;i++) a[i]=read();
	for(lll i=1;i<n;i++)
	{
		x=read();y=read();
		add(x,y);add(y,x);
	}
	deep[1]=1;
	dfs(1,0);
	build(1,1,n);
	init();
	for(lll i=1;i<=q;i++)
	{
		opt=read();
		if(opt==1)
			node=read();
		else if(opt==2)
		{
			x=read();y=read();z=read();
			lll lca,lca1=LCA(x,y),lca2=LCA(x,node),lca3=LCA(y,node);
			if(deep[lca1]>=deep[lca2]&&deep[lca1]>=deep[lca3]) lca=lca1;
			else if(deep[lca2]>=deep[lca1]&&deep[lca2]>=deep[lca3]) lca=lca2;
			else if(deep[lca3]>=deep[lca2]&&deep[lca3]>=deep[lca1]) lca=lca3;
			lll l=LCA(lca,node);
			if(lca==node) insert(1,1,n,1,n,z);
			else if(l==lca&&lca!=node)
			{
				l=node;
				for(lll i=20;i>=0;i--)
					if(deep[f[l][i]]>deep[lca]) l=f[l][i];
				insert(1,1,n,1,n,z);insert(1,1,n,pos[l],pos[l]+size[l]-1,-z);
			}
			else insert(1,1,n,pos[lca],pos[lca]+size[lca]-1,z);
		}
		else if(opt==3)
		{
			x=read();
			lll l=LCA(x,node);
			if(x==node) printf("%lld\n",query(1,1,n,1,n));
			else if(l==x&&x!=node)
			{
				l=node;
				for(lll i=20;i>=0;i--)
					if(deep[f[l][i]]>deep[x]) l=f[l][i];
				printf("%lld\n",query(1,1,n,1,pos[l]-1)+query(1,1,n,pos[l]+size[l],n));
			}
			else printf("%lld\n",query(1,1,n,pos[x],pos[x]+size[x]-1));
		}
	}
	return 0;
}
posted @ 2018-07-15 20:54  Frozen_Heart  阅读(158)  评论(0编辑  收藏  举报