边权化点权的树链剖分

Tree

其实不难想,需要边权下传到,临近的深度较深的节点,边数为 n − 1 n-1 n1,除根外点数也是 n − 1 n-1 n1,所以可以这么做。

插入就是这么做的。

另外在修改链和查询链的时候,一定要注意最后的链,查询和修改的最后的区间是 [ d f n [ s o n [ x ] ] , d f n [ y ] ] [dfn[son[x]],dfn[y]] [dfn[son[x]],dfn[y]]

要注意的是这里求最大值,有取反,所以要维护最小值,因为去反后,最小变最大

别的一般的树剖一样没什么好说的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <deque>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#include <bitset>
#include <set>
#include <map>
//#include <unordered_map>
#define inf 0x7fffffff
//#define ll long long
#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
//const int mod=1000000007;
const int M=5e6;
const int maxn=4;
const int len=4;
const int N=4e5+5;//?????????? 4e8
struct node
{
	int ver,next;
}t[N];
int tot,head[N];
int top[N],fa[N],d[N],son[N],sz[N],num,dfn[N];
int in[N][15];
int n,m;
void init()
{
	for(re i=1;i<=n;i++)
	{
		head[i]=top[i]=fa[i]=d[i]=sz[i]=son[i]=dfn[i]=0;
		for(re j=0;j<=5;j++)  in[i][j]=0;
	}
	tot=num=0;
}
struct tree
{
	int mi,ma,add;
}e[N];
void add(int x,int y)
{
	t[++tot].ver=y;
	t[tot].next=head[x];
	head[x]=tot;
}
void addedge(int x,int y)
{
	add(x,y);add(y,x);
}
void dfs1(int x,int pre)
{
	int ma=-1;
	d[x]=d[pre]+1;
	fa[x]=pre;
	sz[x]=1;
	for(re i=head[x];i;i=t[i].next)
	{
		int y=t[i].ver;
		if(y==pre)  continue;
		dfs1(y,x);
		sz[x]+=sz[y];
		if(ma<sz[y])  ma=sz[y],son[x]=y;
	}
}
void dfs2(int x,int pre)
{
	dfn[x]=++num;
	top[x]=pre;
	if(!son[x])  return;
	dfs2(son[x],pre);
	for(re i=head[x];i;i=t[i].next)
	{
		int y=t[i].ver;
		if(y==fa[x]||y==son[x])  continue;
		dfs2(y,y);
	}
} 
void push(int p)
{
	e[p].ma=max(e[ls(p)].ma,e[rs(p)].ma);
	e[p].mi=min(e[ls(p)].mi,e[rs(p)].mi);
}
void spread(int p)
{
	if(!e[p].add)  return;
	
	e[ls(p)].add^=1;
	e[rs(p)].add^=1;
	e[p].add=0;
	
	e[ls(p)].mi=-e[ls(p)].mi;
	e[ls(p)].ma=-e[ls(p)].ma;
	swap(e[ls(p)].ma,e[ls(p)].mi);
	
	e[rs(p)].mi=-e[rs(p)].mi;
	e[rs(p)].ma=-e[rs(p)].ma;
	swap(e[rs(p)].ma,e[rs(p)].mi);
}
void bulid(int p,int l,int r)
{
	e[p].add=0;
	e[p].ma=-1e18;
	e[p].mi=1e18;
	if(l==r)  return;
	int mid=(l+r)>>1;
	bulid(ls(p),l,mid);bulid(rs(p),mid+1,r);
	push(p);
}
void change(int p,int L,int R,int l,int r,int val)
{
	if(L<=l&&r<=R)
	{
		e[p].ma=e[p].mi=val;
		e[p].add=0;
		return;
	}
	spread(p);
	int mid=(l+r)>>1;
	if(L<=mid)  change(ls(p),L,R,l,mid,val);
	if(mid<R)  change(rs(p),L,R,mid+1,r,val);
	push(p);
}
void update(int p,int L,int R,int l,int r)
{
	if(L<=l&&r<=R)
	{
		e[p].ma=-e[p].ma;
		e[p].mi=-e[p].mi;
		swap(e[p].ma,e[p].mi);
		e[p].add^=1;
		return;
	}
	spread(p);
	int mid=(l+r)>>1;
	if(L<=mid)  update(ls(p),L,R,l,mid);
	if(mid<R)  update(rs(p),L,R,mid+1,r);
	push(p);
}
int ask(int p,int L,int R,int l,int r)
{
	if(L<=l&&r<=R)  return e[p].ma;
	spread(p);
	int mid=(l+r)>>1;
	int ans=-1e18;
	if(L<=mid)  ans=max(ans,ask(ls(p),L,R,l,mid));
	if(mid<R)  ans=max(ans,ask(rs(p),L,R,mid+1,r));
	return ans;
}
int qchain(int x,int y)
{
	int ans=-1e18;
	while(top[x]!=top[y])
	{
		if(d[top[x]]<d[top[y]])  swap(x,y);
		ans=max(ans,ask(1,dfn[top[x]],dfn[x],1,n));
		x=fa[top[x]];
	}
	if(d[x]>d[y])  swap(x,y);
	ans=max(ans,ask(1,dfn[son[x]],dfn[y],1,n));//
	return ans;
}
void mchain(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(d[top[x]]<d[top[y]])  swap(x,y);
		update(1,dfn[top[x]],dfn[x],1,n);
		x=fa[top[x]];
	}
	if(d[x]>d[y])  swap(x,y);
	update(1,dfn[son[x]],dfn[y],1,n);//
}
void solve()
{
	init(); 
	cin>>n;
	for(re i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%lld%lld%lld",&x,&y,&z);
		addedge(x,y);
		in[i][1]=x;in[i][2]=y;in[i][3]=z;
	}
	dfs1(1,1);dfs2(1,1);bulid(1,1,n); 
	for(re i=1;i<n;i++)
	{
		if(d[in[i][1]]<d[in[i][2]])  swap(in[i][2],in[i][1]);
		change(1,dfn[in[i][1]],dfn[in[i][1]],1,n,in[i][3]);
	}
	while(1)
	{
		char op[20];
		int l,r;
		scanf("%s",op);
		if(op[0]=='D')  break;
		scanf("%lld%lld",&l,&r);
		if(op[0]=='Q')  printf("%lld\n",qchain(l,r));
		else if(op[0]=='C')  change(1,dfn[in[l][1]],dfn[in[l][1]],1,n,r);
		else  mchain(l,r);
	}
}
signed main()
{
    int T=1;
    cin>>T;
    for(int index=1;index<=T;index++)
    {
//    	printf("Case %lld:\n",index);
        solve();
//        puts("");
    }
    return 0;
}
/*







*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值