【POJ3237】Tree 树链剖分

题意:

change,把第i条边权值改成v

negate,把a到b路径上所有权值取相反数(*(-1))

query,询问a到b路径上所有权值的最大值


树链剖分。

以前一直不会,但是我恶补LCT了,所以先学一下。

对于现在的水平来说,树剖太水了,自己翻资料吧,我只提供一个还算不错的代码。


扒代码的时候可以用我的这个。


附rand和pai。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
	int u,v,len,next;
}e[N<<1],road[N];
int head[N],cnt;
void add(int u,int v,int len)
{
	++cnt;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
struct Segment_Tree
{
	int l,r;
	int in,ax;
	bool lazy;
}s[N<<2];
int n,m,root=1;
int deep[N],Fa[N],son[N],size[N];// 深度,父节点,重儿子
int top[N],pos[N],len[N],ll[N];
char opt[10];
void init()
{
	cnt=0;
	memset(top,0,sizeof(top));
	memset(son,0,sizeof(son));
	memset(head,0,sizeof(head));
}
void dfs1(int x,int p)// 确定轻重儿子
{
	int i,v,temp=0;
	deep[x]=deep[p]+1;
	size[x]=1;
	Fa[x]=p;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		if(v==p)continue;
		dfs1(v,x);
		size[x]+=size[v];
		ll[v]=e[i].len;
		if(temp<size[v])temp=size[v],son[x]=v;
	}
	return ;
}
void dfs2(int x,int p,int r)// 确定轻重链,并将它们串起来
{
	int i,v;
	pos[x]=++cnt;
	len[cnt]=ll[x];
	top[x]=r;
	if(son[x])dfs2(son[x],x,top[x]);// 先走重链保证dfs序的性质。
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		if(v==p||v==son[x])continue;
		dfs2(v,x,v);
	}
}
void pushup(int x)
{
	s[x].in=min(s[x<<1].in,s[x<<1|1].in);
	s[x].ax=max(s[x<<1].ax,s[x<<1|1].ax);
}
void pushdown(int x)
{
	if(s[x].lazy)// 取反
	{
		if(s[x].l<s[x].r)s[x<<1].lazy^=1,s[x<<1|1].lazy^=1;
		int t=s[x].in;s[x].in=-s[x].ax;s[x].ax=-t;
		s[x].lazy=0;
	}
}
void build(int note,int l,int r)
{
	s[note].lazy=0;
	s[note].l=l,s[note].r=r;
	if(l==r)
	{
		s[note].ax=s[note].in=len[l];
		if(l==1)s[note].in=inf,s[note].ax=-inf;
		return ;
	}
	int mid=l+r>>1;
	build(note<<1,l,mid);
	build(note<<1|1,mid+1,r);
	pushup(note);
}
void change(int note,int L,int R,int x,int y)
{
	pushdown(note);
	if(L==R)
	{
		s[note].in=s[note].ax=y;
		return ;
	}
	int mid=L+R>>1;
	if(x<=mid)change(note<<1,L,mid,x,y),pushdown(note<<1|1);
	else change(note<<1|1,mid+1,R,x,y),pushdown(note<<1);
	pushup(note);
}
int ASK(int note,int L,int R,int l,int r)
{
	if(l>r)return -inf;
	pushdown(note);
	if(L==l&&r==R)return s[note].ax;
	int mid=L+R>>1;
	if(r<=mid)return ASK(note<<1,L,mid,l,r);
	else if(l>mid)return ASK(note<<1|1,mid+1,R,l,r);
	else return max(ASK(note<<1,L,mid,l,mid),ASK(note<<1|1,mid+1,R,mid+1,r));
}
int ask(int a,int b)
{
	int fa,fb,ans=-inf;
	for(fa=top[a],fb=top[b];fa!=fb;a=Fa[top[a]],fa=top[a])
	{
		if(deep[fa]<deep[fb])swap(a,b),swap(fa,fb);
		ans=max(ans,ASK(1,1,n,pos[fa],pos[a]));
	}
	if(a!=b)
	{
		if(deep[a]<deep[b])swap(a,b);
		ans=max(ans,ASK(1,1,n,pos[b]+1,pos[a]));
	}
	return ans;
}
void NEGATE(int note,int L,int R,int l,int r)
{
	if(L==l&&r==R)
	{
		s[note].lazy^=1;
		pushdown(note);
		return ;
	}
	pushdown(note);
	int mid=L+R>>1;
	if(r<=mid)NEGATE(note<<1,L,mid,l,r),pushdown(note<<1|1);
	else if(l>mid)NEGATE(note<<1|1,mid+1,R,l,r),pushdown(note<<1);
	else NEGATE(note<<1,L,mid,l,mid),NEGATE(note<<1|1,mid+1,R,mid+1,r);
	pushup(note);
}
void _negate(int a,int b)
{
	int fa,fb;
	for(fa=top[a],fb=top[b];fa!=fb;a=Fa[top[a]],fa=top[a])
	{
		if(deep[fa]<deep[fb])swap(a,b),swap(fa,fb);
		NEGATE(1,1,n,pos[fa],pos[a]);
	}
	if(a!=b)
	{
		if(deep[a]<deep[b])swap(a,b);
		NEGATE(1,1,n,pos[b]+1,pos[a]);
	}
}
int main()
{
//	freopen("test.in","r",stdin);
//	freopen("my.out","w",stdout);
	int i,j,k,g;
	int a,b,c;
	scanf("%d",&g);
	while(g--)
	{
		init();
		scanf("%d",&n);
		for(i=1;i<n;i++)
		{
			scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].len);
			add(road[i].u,road[i].v,road[i].len);
			add(road[i].v,road[i].u,road[i].len);
		}
		cnt=0;
		dfs1(root,0);
		dfs2(root,0,root);
		build(1,1,n);
		while(scanf("%s",opt),opt[0]!='D')
		{
			scanf("%d%d",&a,&b);
			if(opt[0]=='Q')printf("%d\n",ask(a,b));
			else if(opt[0]=='N')_negate(a,b);
			else change(1,1,n,pos[Fa[road[a].u]==road[a].v?road[a].u:road[a].v],b);
		}
	}
	return 0;
}
rand:

#include <ctime>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	int i,j,k;
	freopen("test.in","w",stdout);
	puts("1");
	srand((unsigned)time(NULL));
	int n=5;
	printf("%d\n",n);
	for(i=1;i<n;i++)
	{
		printf("%d %d %d\n",i+1,rand()%i+1,rand()%14513546);
	}
	for(i=1;i<n;i++)
	{
		int opt=rand()%3;
		if(opt==0)
		{
			printf("CHANGE %d %d\n",rand()%(n-1)+1,rand()%42534567);
		}
		else if(opt==1)
		{
			int a=0,b=0;
			while(a==b)a=rand()%n+1,b=rand()%n+1;
			printf("NEGATE %d %d\n",a,b);
		}
		else 
		{
			int a=0,b=0;
			while(a==b)a=rand()%n+1,b=rand()%n+1;
			printf("QUERY %d %d\n",a,b);
		}
	}
	puts("DONE");
	fclose(stdout);
	return 0;
}
pai

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;

int main()
{
	int i,j,k;
	for(i=1;i<=3000;i++)
	{
		system("rand");
		system("my");
		system("std");
		printf("Case %04d : ",i);
		if(system("fc my.out std.out > NULL")==0)
		{
			puts("AC");
		}
		else 
		{
			puts("WAWAWWAWAWWWA");
			system("pause");
			return 0;
		}
	}
	system("pause");
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值