【树链剖分】权值取反,区间最大

【题面】
有一棵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\n",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

原文地址:https://www.cnblogs.com/tqr06/p/10389115.html

时间: 2024-10-06 13:19:57

【树链剖分】权值取反,区间最大的相关文章

poj 2763 树链剖分(单点更新,区间求值)

http://poj.org/problem?id=2763 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional ro

POJ3237-Tree (树链剖分,线段树区间更新+点更新+区间查询)

两个更新操作,一个将第i条路径权值改为w,一个是将a-b之间所有路径权值取反. 一个查询操作,求a-b之间路径中权值最大的边. 很容易想到维护一个最大最小值,取反就是把最大最小取反交换一下. 开始遇到一个问题就是我把根节点赋值0,上一道题求和没问题,但是这道题会出问题,于是线段树建树的时候从2开始建的,第一次尝试这么写,不过也没什么问题. wa了一天.... 一开始的错是pushdown的时候没有把子节点的fg更新,于是我改了fg[lson]=fg[rson]=1........ 就这样....

【BZOJ-3553】三叉神经树 树链剖分

3553: [Shoi2014]三叉神经树 Time Limit: 160 Sec  Memory Limit: 256 MBSubmit: 347  Solved: 112[Submit][Status][Discuss] Description 计算神经学作为新兴的交叉学科近些年来一直是学术界的热点.一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注.SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构.每个 SHOI

POJ 3237 树链剖分

点击打开链接 题意:给一个树,三种操作,一个是将第I条边的权值改变,一个是将u到v的所有边的权值取反,一个是询问u到v的路径中边的最大值 思路:和模版的树链剖分没什么区别,这题唯一的坑点就是线段树的懒惰标记,只要有更新操作或者查询操作就都要pushdown(),然后改权值的比较简单,单点更新,而区间取反我们可以用两个数组直接模拟,一个最大值的,一个区间最小值的,然后一旦取反了,就将最大值改为负的最小值,而最小值一样改为负的最大值就可以了 #include <vector> #include &

(树链剖分+线段树)POJ - 3237 Tree

前言: 一直听说树链剖分-树链剖分,现在见识一下,,,感觉不是很难0.0 看了一下kuangbin模板基本秒懂 对于点,按重边优先给予每个点一个编号,对于一条重链上的点,编号则是连续的,将所有编号映射到线段树上,即可进行一切区间操作. 对于边的处理,我们将所有边对应到这条边节点更深的那个点上即可. 如果需要的操作只有求和,和单点更新/区间更新,直接用树状数组也是可以的,可能常数大那么一点点. 如果还需要更加强大的操作,显然用splay树维护也是可以的.. 比如树链上所有权值翻转等等..不过,,这

BZOJ 2157 旅游 树链剖分

题目大意:给出一棵树,支持以下操作:1.改变一条边的边权.2.将x到y路径的权值取反.3.查询x到y路径上最大值,最小值和权值和. 思路:好裸的链剖水题啊,唯一麻烦一点地是权值放在了边上,注意一下处理就没问题了.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3

BZOJ 2243 树链剖分

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 题意:中文题目 思路:树链剖分.首先考虑求区间颜色段数的问题, 我们可以用线段树维护:区间左右端点(st,ed),区间颜色段数(val),懒惰标记(lazy:是否整个区间被染成同一种颜色),区间左右端点的颜色(lcolor,rcolor),然后在查询的时候如果当前区间的左子树的右端点的颜色等于右子树的左端点的颜色,那么查询答案要减一.由于树链剖分在查询时是有可能两端的分链一起向上爬

hdu 5242 树链剖分找权值最大的前k条链

http://acm.hdu.edu.cn/showproblem.php?pid=5242 Problem Description It is well known that Keima Katsuragi is The Capturing God because of his exceptional skills and experience in ''capturing'' virtual girls in gal games. He is able to play k games sim

hdu3966 树链剖分(区间更新和单点求值)

http://acm.hdu.edu.cn/showproblem.php?pid=3966 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the ene