奇怪的树 - BIT - 树剖

题目大意:给一颗有根树,每个点是黑色或者白色,支持:翻转一个点的颜色,翻转所有与给定点距离为奇数的点的颜色,求所有黑点与给定点的lca的编号之和。2e5。
题解:首先考虑没有2咋做,类似与动态dp,先树剖一下,然后每个点维护轻边的所有信息,询问的时候有点像是LCT的切换轻重边。考虑如果是翻转整个树的颜色咋做,显然不仅维护黑点同时维护白点的答案,每次翻转整棵树就直接交换两个数组。因为还有距离为奇数的限制,发现这个等价于把点按照深度的奇偶性分类,每次翻转一组,因此再拆成两个即可。上述信息都可以用BIT实现,也就是维护黑白/奇偶两两配对的四种情况即可,复杂度两个log,貌似可以用lct做到一个log。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 200010
#define lint long long
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lb(x) (x&-x)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre;
}e[N<<1];int h[N],etop,in[N],fa[N],dfc,top[N],col[N],sz[N],son[N],d[N],bot[N],tms[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
int fir_dfs(int x,int f=0)
{
    fa[x]=f,sz[x]=1,d[x]=d[f]+1;
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^fa[x])
        {
            sz[x]+=fir_dfs(y,x);
            if(sz[y]>sz[son[x]]) son[x]=y;
        }
    return sz[x];
}
int sec_dfs(int x)
{
    tms[in[x]=++dfc]=x;
    if(son[x]) top[son[x]]=top[x],sec_dfs(son[x]),bot[x]=bot[son[x]];
    else bot[x]=x;
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^fa[x]&&e[i].to!=son[x]) top[y]=y,sec_dfs(y);
    return 0;
}
int c[2][2][N],r[2];lint s[2][2][N];
inline int updc(int *c,int x,int n,int v) { for(;x<=n;x+=lb(x)) c[x]+=v;return 0; }
inline int upds(lint *s,int x,int n,int v) { for(;x<=n;x+=lb(x)) s[x]+=v;return 0; }

inline int qryc(int *c0,int *c1,int x) { int ans=0;for(;x;x-=lb(x)) ans+=c0[x]+c1[x];return ans; }
inline lint qrys(lint *s0,lint *s1,int x) { lint ans=0;for(;x;x-=lb(x)) ans+=s0[x]+s1[x];return ans; }

inline int qryc(int *c0,int *c1,int l,int r) { return qryc(c0,c1,r)-qryc(c0,c1,l-1); }
inline lint qrys(lint *s0,lint *s1,int l,int r) { return qrys(s0,s1,r)-qrys(s0,s1,l-1); }

inline int update(int x,int n,int sgn=-1)
{
    for(int t=d[x]&1,p=col[x];x;x=fa[top[x]])
        updc(c[t][p],in[x],n,1),upds(s[t][p],in[x],n,x),
        updc(c[t][p^1],in[x],n,sgn),upds(s[t][p^1],in[x],n,sgn*x);
    return 0;
}
inline lint query(int x)
{
    int *c0=c[0][r[0]^1],*c1=c[1][r[1]^1];
    lint *s0=s[0][r[0]^1],*s1=s[1][r[1]^1];
    lint ans=qrys(s0,s1,in[top[x]],in[x]);
    if(son[x]) ans+=1ll*x*qryc(c0,c1,in[son[x]],in[bot[x]]);
    for(int y;fa[top[x]];x=fa[top[x]])
        y=fa[top[x]],ans+=qrys(s0,s1,in[top[y]],in[y]),
        ans+=1ll*y*(qryc(c0,c1,in[son[y]],in[bot[y]])-qryc(c0,c1,in[top[x]],in[bot[x]]));
    return ans;
}
int main()
{
    int n=inn(),m=inn(),x,opt;
    for(int i=1;i<=n;i++) col[i]=inn();
    for(int i=1,u,v;i<n;i++)
        u=inn(),v=inn(),add_edge(u,v),add_edge(v,u);
    fir_dfs(1),top[1]=1,sec_dfs(1);
    for(int i=1;i<=n;i++) update(i,n,0);
    while(m--)
        if((opt=inn())==1) x=(d[inn()]&1)^1,r[x]^=1;
        else if(opt==2) col[x=inn()]^=1,update(x,n);
        else printf("%lld\n",query(inn()));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值