码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-02-16 20:50:23      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:space   return   getch   open   之间   答案   gis   else   操作   

【题面】
有一棵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

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

标签:space   return   getch   open   之间   答案   gis   else   操作   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!