树剖经验总结——边权转点权的注意事项

· · 个人记录

P3950 部落冲突
因为一个细节被卡了一个半小时。
让我更迷惑的是以不同的点为根建树竟然 A 掉的点不一样。
组里大佬两分钟找出问题,感觉智商被暴踩。
主要问题是这样的:
题目要求是边修改,于是我自以为是地把边修改转为对深度较深点的点修改。
一试样例竟然过了,心想没什么毛病了。
但是问题来了:
在查询时,两点的 LCA 的权值也被计算了。
但注意了,以我的思路, LCA 的状态其实是其父边的状态,它对答案不应有影响!
由此可见在将边权推为点权时,一定要考虑 LCA 的影响。

修改其实非常简单。
因为树剖查询时,最后当两点在同一重链上时,深度低的点事实上就是 LCA 。
只要忽略掉它的影响就可以了。
上代码:
#include<iostream>
#include<cstdio>
#define ll long long
#define M 300005
#define N 600005
using namespace std;
//-------------------------------------------------------------
ll read()
{
    ll data=0,w=1;
    char c=getchar();
    while(c!='-'&&(c<'0'||c>'9'))
        c=getchar();
    if(c=='-')
        w=-1,c=getchar();
    while(c>='0'&&c<='9')
        data=data*10+c-'0',c=getchar();
    return data*w;
}
//-------------------------------------------------------------
struct edge
{
    ll to,next;
} e[N];
ll head[M],cnt=0;
void adde(ll x,ll y)
{
    cnt++;
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}
//-------------------------------------------------------------
ll n,m;
ll size[M],daddy[M],son[M],dfn[M],dep[M],top[M];
//-------------------------------------------------------------
void dfs1(ll x,ll f,ll deep)
{
    daddy[x]=f;
    dep[x]=deep;
    size[x]=1;
    ll mason=-1,v;
    for(ll u=head[x];u;u=e[u].next)
    {
        v=e[u].to;
        if(v==f)
            continue;
        dfs1(v,x,deep+1);
        size[x]+=size[v];
        if(size[v]>mason)
            mason=size[v],son[x]=v;
    }
}
//-------------------------------------------------------------
ll cmt=0;
void dfs2(ll x,ll t)
{
    dfn[x]=++cmt;
    top[x]=t;
    ll v;
    if(!son[x])
        return ;
    dfs2(son[x],t);
    for(ll u=head[x];u;u=e[u].next)
    {
        v=e[u].to;
        if(v==daddy[x]||v==son[x])
            continue ;
        dfs2(v,v);
    }
}
//-------------------------------------------------------------
ll tre[M],a[M];
ll lowbit(ll x)
{
    return (x&(-x));
}
ll gap(ll x)
{
    ll s=0;
    for(ll i=x;i>=1;i-=lowbit(i))
        s+=tre[i];
    return s;
}
ll dow(ll x)
{
    for(ll i=x;i<=n;i+=lowbit(i))
        tre[i]-=1;
}
ll upo(ll x)
{
    for(ll i=x;i<=n;i+=lowbit(i))
        tre[i]+=1;
}
//-------------------------------------------------------------
bool qran(ll x,ll y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        if((gap(dfn[x])-gap(dfn[top[x]]-1))<0)
            return 1;
        x=daddy[top[x]];
    }
    if(dep[x]<dep[y])
        swap(x,y);
    if(gap(dfn[x])-gap(dfn[y])<0)//就是这里
        return 1;          //原本是dfn[y]-1
    return 0;
}
//-------------------------------------------------------------
ll war[M],o=0;
int main()
{
    cin>>n>>m;
    ll u,v;
    for(ll i=1;i<n;i++)
    {
        u=read();
        v=read();
        adde(u,v);
        adde(v,u);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    for(ll i=1;i<=n;i++)
        tre[i]=0;
    char la;
    for(ll i=1;i<=m;i++)
    {
        cin>>la;
        if(la=='Q')
        {
            u=read();
            v=read();
            if(qran(u,v)==1)
                cout<<"No"<<endl;
            else
                cout<<"Yes"<<endl;
        }
        if(la=='C')
        {
            u=read();
            v=read();
            if(dep[u]<dep[v])
                swap(u,v);
            dow(dfn[u]);
            war[++o]=u;
        }
        if(la=='U')
        {
            u=read();
            upo(dfn[war[u]]);
        }
    }
}