POJ 2763 Housewife Wind - LCA - 树状数组

传送门

题目大意:给定一棵树,支持修改边权和查询两点距离。

显然可以链剖去做。但是注意到dis(x,y)=dis(1,x)+dis(1,y)-2*(dis(1,LCA(x,y)))。

然后修改到x的边的边权等价于让x子树中的所有点的dis(1,y)+=c。

然后显然可以用BIT维护。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define MAXN 100010
#define MAXM 200010
#define MAXL 21
#define lowbit(x) ((x)&(-(x)))
using namespace std;
struct edges{
	int to,pre,wgt,id;
}e[MAXM];int out[MAXN];
int to[MAXN],h[MAXN],etop,d[MAXN];
int in[MAXN],times[MAXN],dfs_clock;
int up[MAXN][MAXL],dep[MAXN],w[MAXN];
int add_edge(int u,int v,int w,int id)
{
	etop++;
	e[etop].to=v;
	e[etop].wgt=w;
	e[etop].id=id;
	e[etop].pre=h[u];
	h[u]=etop;
	return 0;
}
int dfs(int x,int f,int dis,int id)
{
	times[in[x]=++dfs_clock]=x;d[x]=dis;
	up[x][0]=f;dep[x]=dep[f]+1;to[id]=x;
	for(int i=1;i<MAXL;i++)
		up[x][i]=up[up[x][i-1]][i-1];
	for(int i=h[x];i;i=e[i].pre)
		if(e[i].to^f) dfs(e[i].to,x,dis+e[i].wgt,e[i].id);
	out[x]=dfs_clock;return 0;
}
inline int getLCA(int u,int v)
{
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=MAXL-1;i>=0;i--)
		if(dep[up[u][i]]>=dep[v])
			u=up[u][i];
	if(u==v) return u;
	for(int i=MAXL-1;i>=0;i--)
		if(up[u][i]!=up[v][i])
			u=up[u][i],v=up[v][i];
	return up[u][0];
}
struct segment{
	int l,r,s,pt;
	segment *ch[2];
}*rt,seg_pool[MAXN<<1];
queue<segment*> pool;
inline int push_up(segment* &rt)
{
	return rt->s=rt->ch[0]->s+rt->ch[1]->s;
}
inline int update_tags(segment* &rt,int v)
{
	rt->pt+=v;
	rt->s+=(rt->r-rt->l+1)*v;
	return 0;
}
inline int push_down(segment* &rt)
{
	update_tags(rt->ch[0],rt->pt);
	update_tags(rt->ch[1],rt->pt);
	return rt->pt=0;
}
inline int build(segment* &rt,int l,int r)
{
//	rt=pool.front();pool.pop();
	rt=new segment;
	rt->l=l,rt->r=r;rt->ch[0]=rt->ch[1]=NULL;
	rt->s=rt->pt=0;
	if(l==r) return rt->s=d[times[l]];
	int mid=(l+r)>>1;
	build(rt->ch[0],l,mid);
	build(rt->ch[1],mid+1,r);
	push_up(rt);return 0;
}
inline int update(segment* &rt,int s,int t,int v)
{
	int l=rt->l,r=rt->r;
	if(s<=l&&r<=t) return update_tags(rt,v);
	if(rt->pt) push_down(rt);
	int mid=(l+r)>>1;
	if(s<=mid) update(rt->ch[0],s,t,v);
	if(mid<t) update(rt->ch[1],s,t,v);
	return push_up(rt);
}
inline int query(segment* &rt,int p)
{
	int l=rt->l,r=rt->r;
	if(l==r) return rt->s;
	if(rt->pt) push_down(rt);
	int mid=(l+r)>>1;
	if(p<=mid) return query(rt->ch[0],p);
	else return query(rt->ch[1],p);
}
inline int delseg(segment* &rt)
{
	if(rt==NULL) return 0;
	delseg(rt->ch[0]);
	delseg(rt->ch[1]);
	pool.push(rt);rt=NULL;
	return 0;
}
int v[MAXN],n;
inline int update(int x,int val)
{
	for(x;x<=n;x+=lowbit(x))
		v[x]+=val;
	return 0;
}
inline int query(int x)
{
	int ans=0;
	for(x;x;x-=lowbit(x))
		ans+=v[x];
	return ans;
}
int main()
{
	int q,x;
//	for(int i=0;i<(MAXN<<1);i++) pool.push(&seg_pool[i]);
	while(scanf("%d%d%d",&n,&q,&x)!=EOF&&(n||q||x))
	{
		memset(h,0,sizeof(h));etop=0;
		for(int i=1;i<n;i++)
		{
			int u,v;scanf("%d%d%d",&u,&v,&w[i]);
			add_edge(u,v,w[i],i);
			add_edge(v,u,w[i],i);
		}
		dfs_clock=0;
		int root=1;dfs(root,0,0,0);
//		build(rt,1,n);
		memset(v,0,sizeof(v));
		for(int i=1;i<=n;i++) update(i,d[times[i]]-d[times[i-1]]);
		while(q--)
		{
			int opt;scanf("%d",&opt);
			if(!opt)
			{
				int y;scanf("%d",&y);
//				printf("%d\n",query(rt,in[x])+query(rt,in[y])-(query(rt,in[getLCA(x,y)])<<1));
				printf("%d\n",query(in[x])+query(in[y])-(query(in[getLCA(x,y)])<<1));
				x=y;
			}
			else{
				int id,c;scanf("%d%d",&id,&c);
//				update(rt,in[to[id]],out[to[id]],c-w[id]);w[id]=c;
				update(in[to[id]],c-w[id]);
				update(out[to[id]]+1,w[id]-c);w[id]=c;
			}
		}
//		delseg(rt);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值