【线段树】懒标记的维护

Comet OJ - 模拟赛 #2 Day2 圣诞节

题目描述:

摆在 H 君和 R 君面前的是一棵圣诞树。圣诞节就要到了,H 君和 R 君想在圣诞树上挂礼物。

圣诞树上本来是空的,即每个节点都没有礼物。

H 君每次会给你三个值 (u,v,w) 表示他想知道 u到 v的路径上所有值是偶数的数字之和,在这之后,他会将 u到 v的路径上所有值是奇数的数加上 w。

R 君每次会给你三个值 (u,v,w) 表示她想知道 u 到 v 的路径上所有值是奇数的数字之和,在这之后,她会将 u 到 v 的路径上所有值是偶数的数加上 w。

H 君和 R 君忙着挂礼物,就只能让你来回答他们的疑问了。

输入描述:

第一行两个整数 n和 m,表示树的节点个数和操作总数。

第二行到第 n行,每行两个整数 u,v,表示添加一条点 u到点 v 的边。

接下来 m 行,每行四个整数 op,u,v,w。如果 op=1表示这是一次 H 君的询问,如果 op = 2表示这是一次 R 君的询问。 

输出描述:

共 m行,每行一个整数表示第 i次操作的答案。

数据:

对所有数据保证:1<=n<=1.6*10^5, 1<=m<=10^5,op∈1,2, 1<=u,v<=n, 0<=w<=20 。

比赛的时候能想到是树链剖分,但是懒标记的处理的不好,因为是io赛制,最后发现只拿了5分。然后当晚改来改去,隔天早上才把懒标记处理好了。

思路:

题目的要求就是分开处理奇偶数,但是难点在于,奇数在加上一个奇数值就会变成偶数,偶数同理。所以需要维护的是奇偶数的信息,以及在add操作的时候判断当前修改的对象 究竟是奇数还是偶数。

我的线段树是{l,r,on,oe,sumo,sume,lao,lae}

分别表示{左子树,右子树,区间奇数值结点个数,区间偶数值节点的个数,区间奇数值总和,区间偶数值总和,修改于奇数值节点的懒标记,修改于偶数值节点的懒标记}

我一开始的无脑的错误是:判断当前修改对象的奇偶性时(包括add操作和down操作),分开考虑sumo和sume,然后各自操作,以及分开考虑lao和lae的传递。

而正确做法就是综合考虑,用lazy和lazy传递对象的奇偶性,判断该对象的当前奇偶性,然后综合起来一起操作。

哎,主要还是得想清楚。

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int maxn=6e5+5;

vector<int>p[maxn];

int siz[maxn],dep[maxn],fad[maxn],son[maxn];
int top[maxn],tid[maxn],rnk[maxn],cnt;
inline void dfs1(int u,int fa,int d)
{
    dep[u]=d;
    fad[u]=fa;
    siz[u]=1;

    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v==fa)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u,int t)
{
    top[u]=t;
    tid[u]=++cnt;
    rnk[cnt]=u;
    if(!son[u])return;//当前节点不在重链上
    dfs2(son[u],t);
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己
    }
}

struct kkk{
    int l,r;
    int on,en;
    ll sumo,sume;
    int lao,lae;
}tree[maxn<<2];

inline void build(int k,int l,int r)
{
    tree[k].l=l;tree[k].r=r;
    tree[k].sumo=tree[k].sume=tree[k].lao=tree[k].lae=tree[k].en=tree[k].on=0;
    if(l==r)
    {
        tree[k].en=1;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].en=tree[k<<1].en+tree[k<<1|1].en;
}
inline void down(int k)
{

    tree[k<<1].sumo+=tree[k<<1].on*tree[k].lao;
    tree[k<<1].sume+=tree[k<<1].en*tree[k].lae;
    tree[k<<1|1].sumo+=tree[k<<1|1].on*tree[k].lao;
    tree[k<<1|1].sume+=tree[k<<1|1].en*+tree[k].lae;
    if(tree[k].lao%2==1&&tree[k].lae%2==1)
    {
        swap(tree[k<<1].sumo,tree[k<<1].sume);
        swap(tree[k<<1].on,tree[k<<1].en);
        swap(tree[k<<1|1].sumo,tree[k<<1|1].sume);
        swap(tree[k<<1|1].on,tree[k<<1|1].en);
    }
    else if(tree[k].lao&1)//sumo+odd=even
    {
        tree[k<<1].sume+=tree[k<<1].sumo;tree[k<<1].sumo=0;
        tree[k<<1].en+=tree[k<<1].on;tree[k<<1].on=0;
        tree[k<<1|1].sume+=tree[k<<1|1].sumo;tree[k<<1|1].sumo=0;
        tree[k<<1|1].en+=tree[k<<1|1].on;tree[k<<1|1].on=0;
    }
    else if(tree[k].lae&1)
    {
        tree[k<<1].sumo+=tree[k<<1].sume;tree[k<<1].sume=0;
        tree[k<<1].on+=tree[k<<1].en;tree[k<<1].en=0;
        tree[k<<1|1].sumo+=tree[k<<1|1].sume;tree[k<<1|1].sume=0;
        tree[k<<1|1].on+=tree[k<<1|1].en;tree[k<<1|1].en=0;
    }

    if(tree[k<<1].lao%2==0)tree[k<<1].lao+=tree[k].lao;
    else tree[k<<1].lao+=tree[k].lae;
    if(tree[k<<1].lae%2==1)tree[k<<1].lae+=tree[k].lao;
    else tree[k<<1].lae+=tree[k].lae;

    if(tree[k<<1|1].lao%2==0)tree[k<<1|1].lao+=tree[k].lao;
    else tree[k<<1|1].lao+=tree[k].lae;
    if(tree[k<<1|1].lae%2==1)tree[k<<1|1].lae+=tree[k].lao;
    else tree[k<<1|1].lae+=tree[k].lae;
    tree[k].lao=tree[k].lae=0;
}
inline void add(int k,int l,int r,int w,bool iso)
{
    if(l<=tree[k].l&&tree[k].r<=r)
    {
        if(iso)//odd
        {
            if(tree[k].lao%2==0&&tree[k].lae%2==1)tree[k].lao+=w,tree[k].lae+=w;
            else if(tree[k].lao%2==0)tree[k].lao+=w;
            else if(tree[k].lae%2==1)tree[k].lae+=w;
            tree[k].sumo+=tree[k].on*w;
            if(w&1)//odd+odd=even
            {
                tree[k].sume+=tree[k].sumo;tree[k].sumo=0;
                tree[k].en+=tree[k].on;tree[k].on=0;
            }
        }
        else
        {
            if(tree[k].lao%2==1&&tree[k].lae%2==0)tree[k].lao+=w,tree[k].lae+=w;
            else if(tree[k].lao%2==1)tree[k].lao+=w;
            else if(tree[k].lae%2==0)tree[k].lae+=w;
            tree[k].sume+=tree[k].en*w;
            if(w&1)
            {
                tree[k].sumo+=tree[k].sume;tree[k].sume=0;
                tree[k].on+=tree[k].en;tree[k].en=0;
            }
        }
        return;
    }
    if(tree[k].lao||tree[k].lae)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<=mid)add(k<<1,l,r,w,iso);
    if(r>mid)add(k<<1|1,l,r,w,iso);
    tree[k].sumo=tree[k<<1].sumo+tree[k<<1|1].sumo;
    tree[k].sume=tree[k<<1].sume+tree[k<<1|1].sume;
    tree[k].on=tree[k<<1].on+tree[k<<1|1].on;
    tree[k].en=tree[k<<1].en+tree[k<<1|1].en;
}
inline ll query(int k,int l,int r,int iso)
{
    if(l<=tree[k].l&&tree[k].r<=r)
    {
        if(iso)return tree[k].sumo;
        else return tree[k].sume;
    }
    if(tree[k].lao||tree[k].lae)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    ll ans=0;
    if(l<=mid)ans+=query(k<<1,l,r,iso);
    if(r>mid)ans+=query(k<<1|1,l,r,iso);
    return ans;
}
inline void addline(int x,int y,int w,bool iso)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        add(1,tid[top[x]],tid[x],w,iso);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    add(1,tid[x],tid[y],w,iso);
}
inline ll calline(int x,int y,bool iso)
{
    ll ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,tid[top[x]],tid[x],iso);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=query(1,tid[x],tid[y],iso);
    return ans;
}


int main()
{
    int n,m,u,v,w,op;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        p[u].push_back(v);
        p[v].push_back(u);
    }
    memset(son,0,sizeof(son));
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    while(m--)
    {
        scanf("%d%d%d%d",&op,&u,&v,&w);
        if(op==1)
        {
            printf("%lld
",calline(u,v,0));
            addline(u,v,w,1);
        }
        else
        {
            printf("%lld
",calline(u,v,1));
            addline(u,v,w,0);
        }
    }
}
原文地址:https://www.cnblogs.com/kkkek/p/11968774.html