[BZOJ2157] 旅游 树链剖分

模板题,没什么好说的

#include<vector>
#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
const int Lim = 150005;
int n , m;
vector<int> edge[Lim];
struct E {int a , b , c;} e[Lim];

namespace Dfsing{
    int prt[Lim] , son[Lim] , depth[Lim];
    int number[Lim] , siz[Lim] , top[Lim];
    int sign;
    void Dfs_first(int x)
    {
        int Maxson = 0;
        siz[x] = 1;
        for(int i=0,y ; i<(int)edge[x].size() ; i++)
            if( (y = edge[x][i]) != prt[x])
            {
                prt[y] = x;
                depth[y] = depth[x] + 1;
                Dfs_first(y);
                siz[x] += siz[y];
                if(siz[y] > Maxson)
                    son[x] = y , Maxson = siz[y];
            }
    }
    void Dfs_second(int x , int Top_now)
    {
        top[x] = Top_now;
        number[x] = ++sign;
        if(son[x]) Dfs_second(son[x] , Top_now);
        for(int i=0 ; i<(int)edge[x].size() ; i++)
        {
            int y = edge[x][i];
            if(y == prt[x] || y == son[x]) continue;
            Dfs_second(y , y);
        }
    }
}
using namespace Dfsing;
namespace Segment_Tree{
    struct Seg{
        int a , b , Maxx , Minn , sum , rev;
    }   tree[Lim * 4];
    void Build(int v , int L , int R)
    {
        tree[v] = (Seg) {L , R , INT_MIN , INT_MAX , 0 , 0};
        if(L == R) return;
        int mid = (L + R) >> 1;
        Build(v<<1 , L , mid) , Build(v<<1|1 , mid+1 , R);
    }
    void Pushdown(int v)
    {
        if(tree[v].rev && (tree[v].a != tree[v].b))
        {
            int Ls = v<<1 , Rs = v<<1|1;
            tree[Ls].Maxx *= -1 , tree[Ls].Minn *= -1 , tree[Ls].sum *= -1;
            swap(tree[Ls].Maxx , tree[Ls].Minn);
            tree[Ls].rev ^= 1;  /*2ed*/

            tree[Rs].Maxx *= -1 , tree[Rs].Minn *= -1 , tree[Rs].sum *= -1;
            swap(tree[Rs].Maxx , tree[Rs].Minn);
            tree[Rs].rev ^= 1;

            tree[v].rev = 0;    /*1st*/
        }
    }
    void Pushup(int v)
    {
        tree[v].Maxx = max(tree[v<<1].Maxx , tree[v<<1|1].Maxx);
        tree[v].Minn = min(tree[v<<1].Minn , tree[v<<1|1].Minn);
        tree[v].sum = tree[v<<1].sum + tree[v<<1|1].sum;
    }
    void Modify(int v , int goal , int d)
    {
        if(tree[v].a > goal || tree[v].b < goal) return;
        if(tree[v].a == goal && tree[v].b == goal)
        {
            tree[v].Maxx = tree[v].Minn = tree[v].sum = d;
            tree[v].rev = 0;
            return;
        }
        Pushdown(v);
        Modify(v<<1 , goal , d) , Modify(v<<1|1 , goal , d);
        Pushup(v);
    }
    void Reverse(int v , int L , int R)
    {
        if(tree[v].a > R || tree[v].b < L) return;
        if(tree[v].a >= L && tree[v].b <= R)
        {
            tree[v].Maxx *= -1;
            tree[v].Minn *= -1;
            tree[v].sum *= -1;
            swap(tree[v].Maxx , tree[v].Minn);
            tree[v].rev ^= 1;

            return;
        }
        Pushdown(v);
        Reverse(v<<1 , L , R) , Reverse(v<<1|1 , L , R);
        Pushup(v);
    }
    int Get_Sum(int v , int L , int R)
    {
        if(tree[v].a > R || tree[v].b < L) return 0;
        if(tree[v].a >= L && tree[v].b <= R) return tree[v].sum;
        Pushdown(v);
        int t1 = Get_Sum(v<<1 , L , R) , t2 = Get_Sum(v<<1|1 , L , R);
        Pushup(v);
        return t1 + t2;
    }
    int Get_Max(int v , int L , int R)
    {
        if(tree[v].a > R || tree[v].b < L) return INT_MIN;
        if(tree[v].a >= L && tree[v].b <= R) return tree[v].Maxx;
        Pushdown(v);
        int t1 = Get_Max(v<<1 , L , R) , t2 = Get_Max(v<<1|1 , L , R);
        Pushup(v);
        return max(t1 , t2);
    }
    int Get_Min(int v , int L , int R)
    {
        if(tree[v].a > R || tree[v].b < L) return INT_MAX;
        if(tree[v].a >= L && tree[v].b <= R) return tree[v].Minn;
        Pushdown(v);
        int t1 = Get_Min(v<<1 , L , R) , t2 = Get_Min(v<<1|1 , L , R);
        Pushup(v);
        return min(t1 , t2);
    }
}
using namespace Segment_Tree;
namespace Problems{
    void Neg(int u , int v)
    {
        int f1 = top[u] , f2 = top[v];
        while(f1 != f2)
        {
            if(depth[f1] < depth[f2]) {swap(f1 , f2); swap(u,v);}
            Reverse(1 , number[f1] , number[u]);
            u = prt[f1] , f1 = top[u];
        }
        if(u == v) return;
        if(depth[u] > depth[v]) swap(u , v);
        Reverse(1 , number[son[u]] , number[v]);
    }
    int Ask_Sum(int u , int v)
    {
        int f1 = top[u] , f2 = top[v] , sum = 0;
        while(f1 != f2)
        {
            if(depth[f1] < depth[f2]) {swap(f1 , f2); swap(u,v);}
            sum += Get_Sum(1 , number[f1] , number[u]);
            u = prt[f1] , f1 = top[u];
        }
        if(u == v) return sum;
        if(depth[u] > depth[v]) swap(u , v);
        return (sum + Get_Sum(1 , number[son[u]] , number[v]));
    }
    int Ask_M(int u , int v , int way)
    {
        int f1 = top[u] , f2 = top[v];
        int ans = way == 1 ? INT_MIN : INT_MAX;
        while(f1 != f2)
        {
            if(depth[f1] < depth[f2]) {swap(f1 , f2); swap(u,v);}
            if(way == 1) ans = max(ans , Get_Max(1 , number[f1] , number[u]));
                else ans = min(ans , Get_Min(1 , number[f1] , number[u]));
            u = prt[f1] , f1 = top[u];
        }
        if(u == v) return ans;
        if(depth[u] > depth[v]) swap(u , v);
        if(way == 1) ans = max(ans , Get_Max(1 ,  number[son[u]] , number[v]));
            else ans = min(ans , Get_Min(1 ,  number[son[u]] , number[v]));
        return ans;
    }
}
using namespace Problems;

void Solve()
{
    char order[10];
    scanf("%d",&m);
    int u , v;
    while(m--)
    {
        scanf("%s %d %d",order,&u,&v);
        u++ , v++;
        if(order[0] == 'C') Modify(1 , number[e[u-1].a] , v-1);
        else if(order[0] == 'N') Neg(u , v);
        else if(order[0] == 'S') printf("%d\n",Ask_Sum(u , v));
        else
        {
            if(order[1] == 'A') printf("%d\n",Ask_M(u , v , 1));
            else printf("%d\n",Ask_M(u , v ,2));
        }
    }

}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d %d %d",&e[i].a,&e[i].b,&e[i].c);
        e[i].a++ , e[i].b++;
        edge[e[i].a].push_back(e[i].b);
        edge[e[i].b].push_back(e[i].a);
    }
    depth[1] = 1;
    Dfs_first(1);
    Dfs_second(1 , 1);
    Build(1 , 1 , sign);
    for(int i=1;i<n;i++)
    {
        if(depth[e[i].a] < depth[e[i].b]) swap(e[i].a , e[i].b);
        Modify(1 , number[e[i].a] , e[i].c);
    }
    Solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值