【bzoj2157】旅游(树链剖分边权)

题目:

我是超链接

题解:

第一次(?)超200行鼓掌

树链剖分模板题------维护边权,解决方法:把边权放到较深的点中去,这样root就不能进行计算,查询的时候只要找到根的重儿子就行(想想看?)(因为f1!=f2的时候一个点一定在根节点上,另一个点肯定是重链上的点)

第二个不一样的问题就是取反,设置delta数组进行取反,别忘了change值得时候delta变成0

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define MIN -1e9
#define MAX 1e9
#define N 20005
using namespace std;
struct hh
{
	int a,b,z;
}w[20005];                     
int size[N*4],ww[N*4],son[N*4],fa[N*4],deep[N*2+5],delta[N*4+5];
int top[N*4],num[N*4],tree[N*4],totw=0;
int sum[N*4],maxn[N*4],minn[N*4];
int next[N*2+5],point[N*2+5],v[N*2+5],tot=0;
int n,i,a,b,x,m;
void addline(int x,int y)
{
	++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;
	++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void updata(int now)
{
	if (now)
	{
		maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
		sum[now]=sum[now<<1]+sum[now<<1|1];
		minn[now]=min(minn[now<<1],minn[now<<1|1]);
	}
}
void pushdown(int now)
{
	if (delta[now])
	{
		delta[now<<1]^=1;
		delta[now<<1|1]^=1;
		
		int xhh=maxn[now<<1];
		maxn[now<<1]=-minn[now<<1];
		minn[now<<1]=-xhh;
		sum[now<<1]=-sum[now<<1];
		
		xhh=maxn[now<<1|1];
		maxn[now<<1|1]=-minn[now<<1|1];
		minn[now<<1|1]=-xhh;
		sum[now<<1|1]=-sum[now<<1|1];
		
		delta[now]=0;
	}
}
void dfs_1(int now,int dep,int faa)
{
	deep[now]=dep;
	fa[now]=faa;
	size[now]=1;
	int maxx=0;
	for (int i=point[now];i;i=next[i])
	  if (v[i]!=faa)
	  {
	  	dfs_1(v[i],dep+1,now);
	  	size[now]+=size[v[i]];
	  	if (size[v[i]]>maxx)
	  	{
	  		maxx=size[v[i]];
	  		son[now]=v[i];
		}
	  }
}
void dfs_2(int now,int faa)
{
	if (son[faa]!=now) top[now]=now;
	else top[now]=top[faa];
	num[now]=++totw;
	if (son[now])
	{
		dfs_2(son[now],now);
		for (int i=point[now];i;i=next[i])
		  if (v[i]!=son[now] && v[i]!=faa)
		    dfs_2(v[i],now);
	}
}
void build(int now,int l,int r)
{
	if (l==r)
	{
		maxn[now]=ww[tree[l]];
		minn[now]=ww[tree[l]];
		sum[now]=ww[tree[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(now<<1,l,mid);
	build(now<<1|1,mid+1,r);
	updata(now);
}
void change(int now,int l,int r,int x,int v)
{
	if (l==r)
	{
		delta[now]=0;
		maxn[now]=v;
		minn[now]=v;
		sum[now]=v;
		return; 
	}
	pushdown(now);
	int mid=(l+r)>>1;
	if (x<=mid)	change(now<<1,l,mid,x,v);
	else change(now<<1|1,mid+1,r,x,v);
	updata(now);
}
void qf(int now,int l,int r,int lrange,int rrange)
{
	if (lrange<=l && rrange>=r)
	{
		delta[now]^=1;
		int xhh=maxn[now];
		maxn[now]=-minn[now];
		minn[now]=-xhh;
		sum[now]=-sum[now];
		return;
	}
	pushdown(now);
	int mid=(l+r)>>1;
	if (mid>=lrange)
	  qf(now<<1,l,mid,lrange,rrange);
	if (mid<rrange)
	  qf(now<<1|1,mid+1,r,lrange,rrange);
	updata(now);
}
int qmax(int now,int l,int r,int lrange,int rrange)
{
	if (lrange<=l && rrange>=r) return maxn[now];
	pushdown(now);
	int mid=(l+r)>>1;
	int ans=MIN;
	if (mid>=lrange)
	  ans=max(ans,qmax(now<<1,l,mid,lrange,rrange));
	if (mid<rrange)
	  ans=max(ans,qmax(now<<1|1,mid+1,r,lrange,rrange));
	return ans;
}
int qmin(int now,int l,int r,int lrange,int rrange)
{
	if (lrange<=l && rrange>=r) return minn[now];
	pushdown(now);
	int mid=(l+r)>>1;
	int ans=MAX;
	if (mid>=lrange)
	  ans=min(ans,qmin(now<<1,l,mid,lrange,rrange));
	if (mid<rrange)
	  ans=min(ans,qmin(now<<1|1,mid+1,r,lrange,rrange));
	return ans;
}
int qsum(int now,int l,int r,int lrange,int rrange)
{
	if (lrange<=l && rrange>=r) return sum[now];
	pushdown(now);
	int mid=(l+r)>>1;
	int ans=0;
	if (mid>=lrange)
	  ans+=qsum(now<<1,l,mid,lrange,rrange);
	if (mid<rrange)
	  ans+=qsum(now<<1|1,mid+1,r,lrange,rrange);
	return ans;
}
void work(int id)
{
	int u,v;
	scanf("%d%d",&u,&v);
	u++; v++;
	int f1=top[u],f2=top[v],summ=0,maxx=MIN,minn=MAX;
	while (f1!=f2)
	{
		if (deep[f1]<deep[f2]){swap(f1,f2); swap(u,v);}
		switch (id)
		{
			case 1:qf(1,1,n,num[f1],num[u]);break;
			case 2:summ+=qsum(1,1,n,num[f1],num[u]);break;
			case 3:maxx=max(maxx,qmax(1,1,n,num[f1],num[u]));break;
			case 4:minn=min(minn,qmin(1,1,n,num[f1],num[u]));break;
		}
		u=fa[f1];
		f1=top[u];
	}
	if (u!=v)
	{
		if (deep[u]<deep[v]) swap(u,v);
	switch (id)
	  {
	  	case 1:qf(1,1,n,num[son[v]],num[u]);break;
	  	case 2:summ+=qsum(1,1,n,num[son[v]],num[u]);printf("%d\n",summ);break;
	  	case 3:maxx=max(maxx,qmax(1,1,n,num[son[v]],num[u]));printf("%d\n",maxx);break;
	  	case 4:minn=min(minn,qmin(1,1,n,num[son[v]],num[u]));printf("%d\n",minn);break;
	  }
	}
	else
	{
		switch(id)
		{
			case 2:printf("%d\n",summ);break;
			case 3:printf("%d\n",maxx);break;
			case 4:printf("%d\n",minn);break;
		}
	}
}
int main()
{
	scanf("%d",&n);
	for (i=1;i<=n-1;i++) //景点编号为1-N 
	 {
	 	scanf("%d%d%d",&a,&b,&w[i].z);
	 	a++;b++;
	 	addline(a,b);
	 	w[i].a=a; w[i].b=b;
	 }
	dfs_1(1,1,0);
	dfs_2(1,0);
	for (i=1;i<=n-1;i++)
	  if (deep[w[i].a]<deep[w[i].b])//权值落在深点上 
	    ww[w[i].b]=w[i].z;
	  else
	    ww[w[i].a]=w[i].z;
	for (i=1;i<=n;i++) tree[num[i]]=i; 
	build(1,1,n); 
	scanf("%d",&m);
	for (i=1;i<=m;i++)
	{
		char st[10];int www,u,v;
		scanf("%s",st);
		if (st[0]=='C')//变值 
		{
			scanf("%d%d",&x,&www);
			change(1,1,n,num[x+1],www);
		}
		else
		  if (st[0]=='N')//取反 
		  	work(1);
		else
		  if (st[0]=='S')//求和 
		  	work(2);
		else
		  if (st[1]=='A')//最大 
		  	work(3);
		else//最小 
	      work(4);
	} 
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通;、 3本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看ReAdmE.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值