树链剖分权值取反,区间最大
Posted tqr06
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分权值取反,区间最大相关的知识,希望对你有一定的参考价值。
【题面】
有一棵n个点的树,边按照1~n-1标号,每条边拥有一个边权 现在有 m 次操作,每次操作为如下三种之一:
. 1 x y:边x的权值改为y
. 2 x y:将点x到点y路径上的所有边权值变成相反数
. 3 x y:查询点x到点y路径上的最大边权
第一行为两个整数n,m,表示序列长度和操作次数
接下来n-1行,每行三个数a,b,v,表示a,b之间有一条权值为v的边,按照标号1~n-1的顺序给出
接下来m行, 每行以1/2/3作为第一个数,表示操作种类。接下来两个整数,格式如题,表示一次操作
对于每个3操作,输出一行一个整数,表示询问的答案
样例输入
3 3
1 2 3
2 3 2
3 1 3
2 1 3
3 1 3
样例输出
3
-2
约定
对于100%的数据n,<=1e5,给出的所有数绝对值不超过1e9,且保证操作均合法
几乎就是个裸的树剖模板,多了一个异或(xor)控制的取反标记,每次线段树标记下传,维护一下
这题居然花了我三个小时qwq
#include<bits/stdc++.h>
#define fo(i,j,k) for(register int i=j;i<=k;i++)
#define N 100005
#define lson l,mid,x<<1
#define rson mid+1,r,x<<1|1
using namespace std;
int n,m,x,y,v;
vector<int> to[N],val[N];
int fa[N],deep[N],size[N],son[N],top[N],p[N];//树链剖分
int tot,maxx[N<<2],minn[N<<2],X[N],Y[N],a[N],rank[N];
bool flag[N<<2];//是否取反
int max(int a,int b) {return a>b ? a:b;}
int min(int a,int b) {return a<b ? a:b;}
void swap(int &a,int &b) {int t=a;a=b;b=t;}
//重载
void dfs1(int x,int f,int dep)
{
fa[x]=f,deep[x]=dep,size[x]=1;
int y,ms=0;
for(int i=0;i<to[x].size();i++)
{
if((y=to[x][i])!=f)
{
dfs1(y,x,dep+1);
size[x]+=size[y];
a[y]=val[x][i];
if(size[y]>ms) ms=size[y],son[x]=y;
}
}
}
void dfs2(int x,int f,int topf)
{
p[x]=++tot;rank[tot]=x;top[x]=topf;
if(son[x]) dfs2(son[x],x,topf);
int y;
for(int i=0;i<to[x].size();i++) if((y=to[x][i])!=f&&y!=son[x]) dfs2(y,x,y);
}
void fan(int x)
{
flag[x]=flag[x]^1;
swap(maxx[x],minn[x]);
maxx[x]=-maxx[x],minn[x]=-minn[x];
}//取相反数
void Pushup(int x)
{
maxx[x]=max(maxx[x<<1],maxx[x<<1|1]);
minn[x]=min(minn[x<<1],minn[x<<1|1]);
}//维护
void Pushdown(int x) {if(flag[x]) {fan(x<<1);fan(x<<1|1);flag[x]=0;}}
//取反标记下放
void build(int l,int r,int x)
{
flag[x]=0;
if(l==r) maxx[x]=minn[x]=a[rank[l]];
else
{
int mid=(l+r)>>1;
build(lson);build(rson);
Pushup(x);
}
}//建树
void update(int l,int r,int x,int st,int en)
{
if(st<=l&&r<=en) fan(x);
else
{
int mid=(l+r)>>1;
Pushdown(x);
if(en<=mid) update(lson,st,en);
else if(st>mid) update(rson,st,en);
else update(lson,st,en),update(rson,st,en);
Pushup(x);
}
}
void change1(int l,int r,int x,int k,int val)
{
if(l==r) maxx[x]=minn[x]=val;
else
{
int mid=(l+r)>>1;
Pushdown(x);
if(k<=mid) change1(lson,k,val);
else change1(rson,k,val);
Pushup(x);
}
}//单点修改
int query(int l,int r,int x,int st,int en)
{
if(st<=l&&r<=en) return maxx[x];
else
{
int mid=(l+r)>>1;
Pushdown(x);
if(en<=mid) return query(lson,st,en);
else if(st>mid) return query(rson,st,en);
else return max(query(lson,st,en),query(rson,st,en));
}
}
void change2(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
update(1,n,1,p[top[x]],p[x]);
x=fa[top[x]];
}
if(x==y) return;
if(deep[x]<deep[y]) swap(x,y);
update(1,n,1,p[son[y]],p[x]);
}//区间取反
int find(int x,int y)
{
int ans=-1234567890;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans=max(ans,query(1,n,1,p[top[x]],p[x]));
x=fa[top[x]];
}
if(x==y) return ans;
if(deep[x]<deep[y]) swap(x,y);
ans=max(ans,query(1,n,1,p[son[y]],p[x]));
return ans;
}//寻找区间最大值
template<class T> inline void read(T &re)
{
re=0;T sign=1;char tmp;
while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';
while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=re*10+(tmp-'0');re*=sign;
}
int main()
{
freopen("max.in","r",stdin);
freopen("max.out","w",stdout);
int kkksc03;
read(n);read(m);
fo(i,1,n-1)
{
read(x);read(y);read(v);
to[x].push_back(y);
val[x].push_back(v);
to[y].push_back(x);
val[y].push_back(v);
X[i]=x;Y[i]=y;
}
dfs1(1,0,1);dfs2(1,0,1);build(1,n,1);
while(m--)
{
read(kkksc03);read(x);read(y);
if (kkksc03==1)
{
if (deep[X[x]]>deep[Y[x]]) change1(1,n,1,p[X[x]],y);
else change1(1,n,1,p[Y[x]],y);
}
if (kkksc03==2) change2(x,y);
if (kkksc03==3) printf("%d
",find(x,y));
}
return 0;
}
/*
3 3
1 2 3
2 3 2
3 1 3
2 1 3
3 1 3
(3 -2)
8 6
1 2 3
1 5 8
2 3 9
2 4 7
5 8 1
3 6 6
4 7 2
1 4 -5
2 1 7
3 2 6
3 1 7
2 1 8
3 1 5
(9 5 -8)
*/
看到右边的打赏了吗,你可以给我钱让我去买冰阔落!qwq
以上是关于树链剖分权值取反,区间最大的主要内容,如果未能解决你的问题,请参考以下文章