P1505 [国家集训队]旅游

P1505 [国家集训队]旅游

分析

这题和P4114 Qtree1这道题目非常之类似。其中关于如何将边权转化为点权并维护在Qtree1的题解中,需要请看这里题解

在Qtree1这道题目里面,我们只需要维护最大值即可。

但在旅游这道题中,我们需要维护最小值,最大值,总和

但这都不是最麻烦的,最麻烦是将一个区间的值全变为其相反数

难道真的要,依次一个一个的变为对应的相反数嘛?

当然不用,我们有一个常见的小技巧,在面对这类数据结构问题时。

加入懒标记tag,标注此时该区间是否发生了性质的转换

例如,当要求我们,在一个双向链表中,插入,删除,翻转链表时。

我们就会使用懒标记,当插入时,懒标记处于翻转状态,我们就反着插入。

在此题中也是类似。

(线段树结点结构体)

struct Node
{
    int l,r,mmax,mmin,sum,tag;
}tr[N<<2];

我们加入懒标记tag,标记此区间内的所有边权是否发生了翻转。

若发生翻转,那此时区间最大值变最小值,最小值变最大值,总和变为相反数

那pushdown函数长什么样子呢

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag)
    {
        left.tag ^= root.tag;
        change(left);
        right.tag ^= root.tag;
        change(right); 
        root.tag = 0;
    }
}

其中的change函数,就是对区间的翻转操作

void change(Node &u)
{
    swap(u.mmax,u.mmin);
    u.mmax = -u.mmax,u.mmin = -u.mmin;
    u.sum = -u.sum;
}

其他的操作就是正常的树剖和线段树了;

其中对于将边权变为点权后,从u->v的路径中,对LCA的处理,请务必看一下Qtree1

AC_code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10,M = N*2;
struct Node
{
    int l,r,mmax,mmin,sum,tag;
}tr[N<<2];
int h[N],e[M],ne[M],w[M],idx;
int id[N],nw[N],top[N],ts;
int son[N],fa[N],val[N],e2u[N],dep[N],sz[N];
int n;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs1(int u,int pa,int depth)
{
    sz[u] = 1,fa[u] = pa,dep[u] = depth;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==pa) continue;
        val[j] = i/2+1;
        e2u[i/2+1] = j;
        dfs1(j,u,depth+1);
        if(sz[son[u]]<sz[j]) son[u] = j;
        sz[u] += sz[j];
    }
}

void dfs2(int u,int tp)
{
    id[u] = ++ts,top[u] = tp,nw[ts] = w[val[u]];
    if(!son[u]) return ;
    dfs2(son[u],tp);
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==son[u]||j==fa[u]) continue;
        dfs2(j,j);
    }
}

void pushup(int u)
{
    tr[u].mmax = max(tr[u<<1].mmax,tr[u<<1|1].mmax);
    tr[u].mmin = min(tr[u<<1].mmin,tr[u<<1|1].mmin);
    tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}

void change(Node &u)
{
    swap(u.mmax,u.mmin);
    u.mmax = -u.mmax,u.mmin = -u.mmin;
    u.sum = -u.sum;
}

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag)
    {
        left.tag ^= root.tag;
        change(left);
        right.tag ^= root.tag;
        change(right); 
        root.tag = 0;
    }
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u] = {l,r,nw[l],nw[l],nw[l],0};
        return ;
    }
    tr[u] = {l,r,0,0,0,0};
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}

void modify(int u,int l,int r,bool f,int k2)
{
    if(l<=tr[u].l&&tr[u].r<=r) 
    {
        if(!f) tr[u].mmax = tr[u].mmin = tr[u].sum = k2;
        else change(tr[u]),tr[u].tag ^= 1;
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,f,k2);
    if(r>mid) modify(u<<1|1,l,r,f,k2);
    pushup(u);
}

int query(int u,int l,int r,int type)
{
    // cout<<u<<" "<<tr[u].l<<" "<<tr[u].r<<endl;
    if(l<=tr[u].l&&tr[u].r<=r) 
    {
        if(type==1) return tr[u].sum;
        if(type==2) return tr[u].mmax;
        return tr[u].mmin;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    int res = 0;
    if(type==2) res = -1e9;
    if(type==3) res = 1e9;
    if(l<=mid) 
    {
        if(type==1) res += query(u<<1,l,r,type);
        if(type==2) res = max(res,query(u<<1,l,r,type));
        if(type==3) res = min(res,query(u<<1,l,r,type));
    }
    if(r>mid) 
    {
        if(type==1) res += query(u<<1|1,l,r,type);
        if(type==2) res = max(res,query(u<<1|1,l,r,type));
        if(type==3) res = min(res,query(u<<1|1,l,r,type));
    }
    pushup(u);
    return res;
}

int main()
{
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++)
    {
        int a,b,c;cin>>a>>b>>c;
        a++,b++;
        w[i+1] = c;
        add(a,b),add(b,a);
    }
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    int m;cin>>m;
    while(m--)
    {
        string s;cin>>s;
        int x,y,res;cin>>x>>y;
        if(s=="C") modify(1,id[e2u[x]],id[e2u[x]],0,y);
        else if(s=="N")
        {
            x++,y++;
            if(x==y) continue;
            while(top[x]!=top[y])
            {
                if(dep[top[x]]<dep[top[y]]) swap(x,y);
                modify(1,id[top[x]],id[x],1,0);
                x = fa[top[x]];
            }
            if(dep[x]<dep[y]) swap(x,y);
            modify(1,id[y]+1,id[x],1,0);
        }
        else if(s=="SUM")
        {
            x++,y++;
            res = 0;
            if(x==y) puts("0");
            else
            {
                while(top[x]!=top[y])
                {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    res+=query(1,id[top[x]],id[x],1);
                    x = fa[top[x]];
                }
                if(dep[x]<dep[y]) swap(x,y);
                res += query(1,id[y]+1,id[x],1);
                printf("%d\n",res);
            }
        }
        else if(s=="MAX")
        {
            x++,y++;
            res = -1e9;
            if(x==y) puts("0");
            else
            {
                while(top[x]!=top[y])
                {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    res= max(res,query(1,id[top[x]],id[x],2));
                    x = fa[top[x]];
                }
                if(dep[x]<dep[y]) swap(x,y);
                res = max(res,query(1,id[y]+1,id[x],2));
                printf("%d\n",res);
            }
        }
        else 
        {
            x++,y++;
            res = 1e9;
            if(x==y) puts("0");
            else
            {
                while(top[x]!=top[y])
                {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    res= min(res,query(1,id[top[x]],id[x],3));
                    x = fa[top[x]];
                }
                if(dep[x]<dep[y]) swap(x,y);
                res = min(res,query(1,id[y]+1,id[x],3));
                printf("%d\n",res);
            }
        }
    }
    return 0;
}
posted @ 2022-03-20 00:27  艾特玖  阅读(56)  评论(0)    收藏  举报