luogu 5354 [Ynoi2017]由乃的OJ LCT+位运算

如果做过起床困难综合征的话应该很快就能有思路,没做过那道题的话还真是挺费劲的. 

思路就是:维护将全 0 和全 1 带入到链中的值,然后按高位贪心. 

这段代码十分优美,利用了按位取反等骚操作: 

struct node 
{    
    ll f0,f1;   
    node operator+(const node &b) const 
    {
        node a; 
        a.f0=(~f0&b.f0)|(f0&b.f1);      
        a.f1=(~f1&b.f0)|(f1&b.f1);   
        return a; 
    }
}f[N],L[N],R[N];   

code:

#include <bits/stdc++.h> 
#define N 100007     
#define ll unsigned long long 
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)    
using namespace std; 
int n,m,k,edges; 
int hd[N],to[N<<1],nex[N<<1];  
void addedge(int u,int v) 
{ 
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;     
} 
struct node 
{    
    ll f0,f1;   
    node operator+(const node &b) const 
    {
        node a; 
        a.f0=(~f0&b.f0)|(f0&b.f1);      
        a.f1=(~f1&b.f0)|(f1&b.f1);   
        return a; 
    }
}f[N],L[N],R[N];    
struct Link_Cut_Tree
{   
    #define lson p[x].ch[0] 
    #define rson p[x].ch[1] 
    int sta[N];   
    struct Node 
    {    
        int ch[2],f,rev;            
    }p[N];     
    int get(int x) 
    {
        return p[p[x].f].ch[1]==x; 
    }
    int isrt(int x) 
    {
        return !(p[p[x].f].ch[0]==x||p[p[x].f].ch[1]==x); 
    }      
    void pushup(int x) 
    {
        L[x]=R[x]=f[x];  
        if(lson) L[x]=L[lson]+L[x], R[x]=R[x]+R[lson];     
        if(rson) L[x]=L[x]+L[rson], R[x]=R[rson]+R[x];     
    }
    void rotate(int x) 
    {
        int old=p[x].f,fold=p[old].f,which=get(x);  
        if(!isrt(old)) p[fold].ch[p[fold].ch[1]==old]=x;   
        p[old].ch[which]=p[x].ch[which^1],p[p[old].ch[which]].f=old; 
        p[x].ch[which^1]=old,p[old].f=x,p[x].f=fold; 
        pushup(old),pushup(x); 
    }
    void mark(int x) 
    {
        if(!x) return; 
        swap(lson,rson), swap(L[x],R[x]),p[x].rev^=1;  
    }
    void pushdown(int x) 
    {
        if(p[x].rev) 
        { 
            p[x].rev=0; 
            if(lson) mark(lson); 
            if(rson) mark(rson); 
        } 
    }
    void splay(int x) 
    {
        int u=x,v=0,fa; 
        for(sta[++v]=u;!isrt(u);u=p[u].f) sta[++v]=p[u].f;  
        for(;v;--v) pushdown(sta[v]);   
        for(u=p[u].f;(fa=p[x].f)!=u;rotate(x)) 
            if(p[fa].f!=u) 
                rotate(get(fa)==get(x)?fa:x);   
    }
    void Access(int x) 
    {
        for(int y=0;x;y=x,x=p[x].f) 
        {
            splay(x);  
            rson=y; 
            pushup(x);  
        }
    }
    void makeroot(int x) 
    {
        Access(x),splay(x),mark(x); 
    } 
    void split(int x,int y) 
    {
        makeroot(x), Access(y), splay(y);  
    }   
    void link(int x,int y)
    { 
        makeroot(x), p[x].f=y;    
    }     
    void cut(int x,int y) 
    {
        makeroot(x),Access(y),splay(y);  
        p[y].ch[0]=p[x].f=0;  
        pushup(y);    
    }  
    #undef lson 
    #undef rson  
}lct;  
void solve(int x,int y,ll z) 
{
    lct.split(x,y);    
    int i;   
    ll re=0;    
    for(i=k-1;i>=0;--i) 
    { 
        if(L[y].f0&(1ll<<i)) re+=(1ll<<i);   
        else if((L[y].f1&(1ll<<i)) && (1ll<<i)<=z) re+=(1ll<<i), z-=(1ll<<i);      
    } 
    printf("%llu\n",re);    
}      
void dfs(int u,int ff) 
{ 
    lct.p[u].f=ff;     
    for(int i=hd[u];i;i=nex[i])     
        if(to[i]!=ff) dfs(to[i],u);
}  
int main() 
{ 
    int i,j;   
    // setIO("input"); 
    scanf("%d%d%d",&n,&m,&k);       
    for(i=1;i<=n;++i) 
    {
        int op; 
        ll y; 
        scanf("%d%llu",&op,&y);    
        if(op==1) f[i]=(node){0ll,y};   
        if(op==2) f[i]=(node){y,~0ll};      
        if(op==3) f[i]=(node){y,~y}; 
        lct.pushup(i);          
    }
    for(i=1;i<n;++i) 
    {   
        int u,v; 
        scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);    
    }              
    dfs(1,0);    
    for(i=1;i<=m;++i) 
    {
        int op; 
        scanf("%d",&op); 
        if(op==1) 
        {
            int x,y; 
            ll z; 
            scanf("%d%d%llu",&x,&y,&z);     
            solve(x,y,z);   
        }
        else 
        {
            int x,y; 
            ll z; 
            scanf("%d%d%llu",&x,&y,&z);       
            lct.Access(x); 
            lct.splay(x);  
            if(y==1) f[x]=(node){0ll,z};     
            if(y==2) f[x]=(node){z,~0ll};  
            if(y==3) f[x]=(node){z,~z};        
            lct.pushup(x);          
        }
    }
    return 0;     
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值