1. 程式人生 > >【樹鏈剖分】權值取反,區間最大

【樹鏈剖分】權值取反,區間最大

尋找 name 之間 一個數 sign 數據 min swa 序列

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

【樹鏈剖分】權值取反,區間最大