• [洛谷]P3613 睡觉困难综合征


    题目大意:给出一棵n个点的树,每个点有一个运算符(与、或、异或)和一个数,支持两种操作,第一种修改一个点的运算符和数,第二种给出x,y,z,询问若有一个0~z之间的数从点x走到点y(简单路径),并且对路径上经过的点做对应的运算,最终最大能是多少。(n,操作数<=100,000,数字在[0,2^64)之间)

    思路:洛谷改编NOI的一道神题,树剖/LCT维护若一开始全是0/全是1,经过一条链后各位会变成什么,用位运算合并信息,然后每个询问,从高位往低位贪心,每次取0和1中经过这条链后得到的较大值,若相同则取0,总复杂度O(nlogn)/O(nlogn^2)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll unsigned long long
    inline ll read()
    {
        ll x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    #define L(x) c[x][0]
    #define R(x) c[x][1]
    struct edge{int nx,t;}e[MN*2+5];
    struct data{ll f[2];}lf[MN+5],rf[MN+5],f[MN+5];
    data operator+(const data&a,const data&b)
    {
        return (data){~a.f[0]&b.f[0]|a.f[0]&b.f[1],
                      ~a.f[1]&b.f[0]|a.f[1]&b.f[1]};
    }
    int h[MN+5],en,fa[MN+5],c[MN+5][2],rv[MN+5],z[MN+5],zn;
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void dfs(int x)
    {
        for(int i=h[x];i;i=e[i].nx)
            if(e[i].t!=fa[x])fa[e[i].t]=x,dfs(e[i].t);
    }
    inline void up(int x)
    {
        lf[x]=rf[x]=f[x];
        if(L(x))lf[x]=lf[L(x)]+lf[x],rf[x]=rf[x]+rf[L(x)];
        if(R(x))lf[x]=lf[x]+lf[R(x)],rf[x]=rf[R(x)]+rf[x];
    }
    void init(int x,int o,ll z)
    {
        if(o==1)f[x]=(data){0,z};
        if(o==2)f[x]=(data){z,-1};
        if(o==3)f[x]=(data){z,~z};
        up(x);
    }
    inline void rev(int x){rv[x]^=1;swap(L(x),R(x));swap(lf[x],rf[x]);}
    inline void down(int x){if(rv[x])rev(L(x)),rev(R(x)),rv[x]=0;}
    inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;}
    void rotate(int x)
    {
        int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1;
        if(isc(f))c[ff][R(ff)==f]=x;
        fa[f]=x;fa[x]=ff;fa[c[x][r]]=f;
        c[f][l]=c[x][r];up(c[x][r]=f);
    }
    void splay(int x)
    {
        for(int i=z[zn=1]=x;isc(i);)i=z[++zn]=fa[i];
        for(;zn;--zn)down(z[zn]);
        for(int f;isc(x);rotate(x))
            if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f);
        up(x);
    }
    void access(int x)
    {
        for(int i=0;x;x=fa[i=x])splay(x),R(x)=i;
    }
    int main()
    {
        int n,m,i,x,u;ll z,ans,f0,f1;
        n=read();m=read();read();
        for(i=1;i<=n;++i)x=read(),init(i,x,read());
        for(i=1;i<n;++i)ins(read(),read());
        dfs(1);
        while(m--)
            if(read()<2)
            {
                access(x=read());splay(x);rev(x);
                access(x=read());splay(x);
                z=read();ans=u=0;
                for(i=64;i--;)
                    if(u||(z&(1LLU<<i)))
                    {
                        f0=lf[x].f[0]&(1LLU<<i);
                        f1=lf[x].f[1]&(1LLU<<i);
                        if(f0>=f1)u=1;
                        ans|=max(f0,f1);
                    }
                    else ans|=lf[x].f[0]&(1LLU<<i);
                printf("%llu
    ",ans);
            }
            else x=read(),i=read(),splay(x),init(x,i,read());
    }
  • 相关阅读:
    【我读cachecloud】cachecloud-open-web模块controller
    【我读cachecloud】cachecloud项目概述
    [转]Kerberos协议
    【shell】我的wait为什么不能用
    【 一次性密码】TOTP
    【shell】再看一眼find--find使用中遇到的问题分析
    我知道点redis-单机数据库(RDB持久化)
    我知道点redis-数据结构与对象(对象)-对象实现
    我知道点redis-数据结构与对象(对象)-对象存储
    我知道点redis-数据结构与对象(链表)
  • 原文地址:https://www.cnblogs.com/ditoly/p/Luogu3613.html
Copyright © 2020-2023  润新知