POJ 2763 树链剖分+线段树维护区间和

这题是我第一次自己查错并且A掉的树剖模板题。

思路很简单,树剖后扔到线段树里就行了。

唯一困难点的是

1.题目给的是边权值,要转为点值,那么直接把值赋给连接边的两点中深度较大的一点

2.修改时,是给编号修改,为了方便,我直接开的几个数组来装边上的信息

//查了半天错,结果是线段树打错了个字母。。。

AC代码如下

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cassert>
#include <sstream>
#include <numeric>
#include <climits>
#include <string>
#include <cctype>
#include <ctime>
#include <iomanip>
#include <cmath>
#include <vector>
#include <queue>
#include <list>
#include <map>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define INF 200100
using namespace std;
struct data{
	int to,len,next;
}bian[INF*2];
struct node{
	int l,r,sum;
}tr[INF*4];
int n,q,s;
int cnt=0,siz[INF],son[INF],fa[INF],id[INF],top[INF],fanid[INF],deep[INF];
int size,first[INF],a[INF];
bool vis[INF];
int from[INF],too[INF],len[INF],pos,val;
int test,to;
void add(int x,int y,int z)
{
	size++;
	bian[size].next=first[x];
	first[x]=size;
	bian[size].to=y;
	bian[size].len=z;
}
void init()
{
	cnt=size=0;
	memset(first,0,sizeof(first));
	memset(siz,0,sizeof(siz));
	memset(fa,0,sizeof(fa));
	memset(deep,0,sizeof(deep));
	memset(top,0,sizeof(top));
	memset(id,0,sizeof(id));
	memset(son,0,sizeof(son));
	memset(vis,0,sizeof(vis));
}
void dfs1(int u,int last)
{
	vis[u]=1;
	siz[u]=1;
	fa[u]=last;
	deep[u]=deep[last]+1;
	for(int i=first[u];i;i=bian[i].next)
	{
		int to=bian[i].to;
		if(to==fa[u]||vis[to])continue;
		a[to]=bian[i].len;
		dfs1(to,u);
		siz[u]+=siz[to];
		if(son[u]==0)son[u]=to;
		else if(siz[son[u]]<siz[to])
			son[u]=to;
	}
}
void dfs2(int u,int topp)
{
	vis[u]=1;
	id[u]=++cnt;
	top[u]=topp;
	fanid[cnt]=u;
	if(son[u])dfs2(son[u],topp);
	for(int i=first[u];i;i=bian[i].next)
	{
		int to=bian[i].to;
		if(to==fa[u]||to==son[u]||vis[to])continue;
		dfs2(to,to);
	}
}
void update(int k)
{
	tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
}
void build(int k,int s,int t)
{
	tr[k].l=s;tr[k].r=t;
	if(s==t)
	{
		tr[k].sum=a[fanid[s]];
		return;
	}
	int mid=s+t>>1;
	build(k<<1,s,mid);
	build(k<<1|1,mid+1,t);
	update(k);
}
void modify(int k,int pos,int val)
{
	if(tr[k].l==tr[k].r){
		tr[k].sum=val;
		return;
	}
	int mid=tr[k].l+tr[k].r>>1;
	if(pos<=mid)modify(k<<1,pos,val);
	else modify(k<<1|1,pos,val);
	update(k);
}
int query(int k,int s,int t)
{
	if(s<=tr[k].l&&tr[k].r<=t)
		return tr[k].sum;	
	int mid=tr[k].l+tr[k].r>>1;
	int res=0;
	if(t<=mid)
		res+=query(k<<1,s,t);
	else 
	if(s>mid)	
		res+=query(k<<1|1,s,t);
	else 
		res+=query(k<<1,s,mid)+query(k<<1|1,mid+1,t);
	return res;
}
int solvequery(int x,int y)
{
	int sum=0;	
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		sum+=query(1,id[top[x]],id[x]);
		x=fa[top[x]];
	}
	if(x==y)return sum;
	if(deep[x]>deep[y])swap(x,y);
	sum+=query(1,id[x]+1,id[y]);
	return sum;
}
int main()
{
//	freopen("in.in","r",stdin);
	while(scanf("%d%d%d",&n,&q,&s)!=EOF)
	{
		for(int i=1;i<n;i++)
		{
			scanf("%d%d%d",&from[i],&too[i],&len[i]);
			add(from[i],too[i],len[i]);
			add(too[i],from[i],len[i]);
		}
		dfs1(1,0);
		memset(vis,0,sizeof(vis));
		dfs2(1,1);
		for(int i=1;i<n;i++)
		{
			if(deep[from[i]]<deep[too[i]])
                swap(from[i],too[i]);
            a[from[i]]=len[i];
		}
		build(1,1,n);
		while(q--)
		{
			scanf("%d",&test);
			if(test){
				scanf("%d%d",&pos,&val);
				modify(1,id[from[pos]],val);
			}
			else{
				scanf("%d",&to);
				cout<<solvequery(s,to)<<endl;
				s=to;
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值