[YNOI2017]bzoj 4811 由乃的OJ - 树剖 - 线段树

52 篇文章 0 订阅
40 篇文章 0 订阅

树剖,线段树维护每一位经过这个区间从左到右和从右到左0和1分别变成了啥,三个log稳T。发现其实只需要维护00000…000和1111…111会变成啥即可,这样就两个log了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<utility>
#define ull unsigned long long
#define fir first
#define sec second
#define mp make_pair
#define N 100010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<ull,int> pui;
struct edges{
    int to,pre;
}e[N<<1];int top[N],d[N],h[N],etop,opt[N],in[N],tm[N];
int dfs_clock,sz[N],son[N],fa[N];ull all,x[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
inline ull gv(ull z,int p) { return z&(1ull<<p); }
struct msg{
    ull v0,v1;msg(ull all=0ull) { v0=0ull,v1=all; }
    inline msg& operator=(const msg &m)
    {   return v0=m.v0,v1=m.v1,*this;   }
    inline msg& operator=(pui x)
    {
        if(x.sec==1) v0=0ull,v1=x.fir;//&
        if(x.sec==2) v0=x.fir,v1=all;//|
        if(x.sec==3) v0=x.fir,v1=all^x.fir;//^
        return *this;
    }
    inline msg operator+(const msg &b)const
    {
        const msg &a=*this;msg c;
        c.v0=(a.v0&b.v1)^((a.v0^all)&b.v0),
        c.v1=(a.v1&b.v1)^((a.v1^all)&b.v0);
        return c;
    }
    inline msg& operator+=(const msg &m)
    {   return (*this)=(*this)+m;   }
    inline int show() { debug(v0)sp,debug(v1)ln;return 0; }
}lst[50];
struct segment{
    int l,r;
    segment *ch[2];
    msg ltr,rtl;
}*rt;
int push_up(segment* &rt)
{   return rt->ltr=rt->ch[0]->ltr+rt->ch[1]->ltr,rt->rtl=rt->ch[1]->rtl+rt->ch[0]->rtl,0; }
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r;int mid=(l+r)>>1;
    if(l==r) return rt->ltr=rt->rtl=mp(x[tm[l]],opt[tm[r]]),0;//,debug(l)sp,debug(tm[l])sp,debug(x[tm[l]])sp,debug(opt[tm[r]])ln,rt->ltr.show();
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);//,debug(l)sp,debug(r)ln,rt->ltr.show(),rt->rtl.show();
}
int update(segment* &rt,int p,pui v)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(l==r) return rt->ltr=rt->rtl=v,0;
    return update(rt->ch[p>mid],p,v),push_up(rt);
}
msg query_ltr(segment* &rt,int s,int t)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return rt->ltr;msg ans(all);
    if(s<=mid) ans+=query_ltr(rt->ch[0],s,t);
    if(mid<t) ans+=query_ltr(rt->ch[1],s,t);
    return ans;
}
msg query_rtl(segment* &rt,int s,int t)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return rt->rtl;msg ans(all);
    if(mid<t) ans+=query_rtl(rt->ch[1],s,t);
    if(s<=mid) ans+=query_rtl(rt->ch[0],s,t);
    return ans;
}
int fir_dfs(int x,int f=0)
{
    d[x]=d[fa[x]=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)
{
    tm[in[x]=++dfs_clock]=x;
    if(son[x]) top[son[x]]=top[x],sec_dfs(son[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;
}
inline int getLCA(int x,int y)
{
    for(;top[x]^top[y];x=fa[top[x]])
        if(d[top[x]]<d[top[y]]) swap(x,y);
    return d[x]<d[y]?x:y;
}
msg query(int x,int y,msg ans=msg(all))
{
    int c=getLCA(x,y),t=0;
    while(d[top[x]]>=d[c]) ans+=query_rtl(rt,in[top[x]],in[x]),x=fa[top[x]];
    if(d[x]>=d[c]) ans+=query_rtl(rt,in[c],in[x]);
    while(d[top[y]]>d[c]) lst[++t]=query_ltr(rt,in[top[y]],in[y]),y=fa[top[y]];
    if(d[y]>d[c]) lst[++t]=query_ltr(rt,in[c]+1,in[y]);
    for(int i=t;i;i--) ans+=lst[i];return ans;
}
ull get_ans(int x,int y,ull z,int k,ull ans=0ull)
{
    msg res=query(x,y);
    for(int i=k-1,eql=1;i>=0;i--)
    {
        ull v0=gv(res.v0,i),v1=gv(res.v1,i);
        if(eql)
            if(gv(z,i))
                if(v0<v1) ans|=v1;
                else ans|=v0,eql=0;
            else ans|=v0;
        else ans|=max(v0,v1);
    }
    return ans;
}
int main()
{
    int n,m,k;scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<k;i++) all|=(1ull<<i);
    for(int i=1;i<=n;i++) scanf("%d%llu",&opt[i],&x[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        add_edge(x,y),add_edge(y,x);
    }
    fir_dfs(1),top[1]=1,sec_dfs(1),build(rt,1,n);
    while(m--)
    {
        int kd,x,y;ull z;scanf("%d%d%d%llu",&kd,&x,&y,&z);
        if(kd==1) printf("%llu\n",get_ans(x,y,z,k));
        else update(rt,in[x],make_pair(z,y));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值