Ynoi 2017 由乃的OJ

由乃的OJ

题目链接

Solution

首先很显然每一位计算的结果是独立的。
先对树进行树链剖分,每一条重链维护一棵线段树,每个线段树区间维护两个数组 ( t 0 , t 1 ) (t_0,t_1) (t0,t1)分别表示某个数某一位为 0 / 1 0/1 0/1时经过这段区间的运算这一位会变成 0 0 0还是 1 1 1,这两个数组可以用两个 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned long long压起来,但运算顺序可能是深度从大到小,也可能是从小到大,所以要维护两对 ( t 0 , t 1 ) (t_0,t_1) (t0,t1)。修改都是线段树单点修改,询问的话就先把对应链上的 ( t 0 , t 1 ) (t_0,t_1) (t0,t1)求出来,然后贪心的从高位往低位依次确定答案即可。

时间复杂度 O ( n l o g 2   n ) O(n log ^2\ n) O(nlog2 n)

Code

#include
#include
#include
#include
 
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
 
using namespace std;
typedef long long ll;
typedef unsigned long long kk;
 
const ll N=52e4,M=N<<1,K=N*8,mo=1e9+7;
const kk U=((((kk)1<<63)-1)<<1)^1;
 
int ls[K],rs[K];
kk t[K][2][2];
 
int n,m,x,y,ko,oo;
int la[N],lb[M],ne[M];
int size[N],hs[N],gf[N],fa[N],dep[N],len[N],pp[N];
 
int fh[N]; 
kk bq[N];
kk t0,t1;
int f[N][20];
int yy[N][3];
 
inline void llb(int a,int b)
{ne[++oo]=la[a]; la[a]=oo; lb[oo]=b;}
 
inline int read()
{
    int o=0; char ch=' ';
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+(ch^48);
    return o; 
}
 
inline kk _read()
{
    kk o=0; char ch=' ';
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+(ch^48);
    return o;
}
 
inline void dg(int o)
{
    size[o]=1;
    for(int y=la[o];y;y=ne[y])
    if(!fa[lb[y]]){
        fa[lb[y]]=o; 
        f[lb[y]][0]=o;
        for(int l=0;f[f[lb[y]][l]][l];++l)
        f[lb[y]][l+1]=f[f[lb[y]][l]][l];
        dep[lb[y]]=dep[o]+1;
        dg(lb[y]);
        size[o]+=size[lb[y]];
        if(size[lb[y]]>size[hs[o]])hs[o]=lb[y];
    }
}
 
inline void dfs(int o)
{
    ++len[gf[o]];
    for(int y=la[o];y;y=ne[y])
    if(fa[lb[y]]==o){
        if(lb[y]==hs[o])gf[lb[y]]=gf[o];
        else gf[lb[y]]=lb[y];
        dfs(lb[y]);
    }
}
 
inline void build(int o,int l,int r)
{
    if(l==r){
        t[o][1][1]=t[o][1][0]=t[o][0][0]=t[o][0][1]=0;
        return;
    }
    int mid=l+r>>1;
    ls[o]=++ko;
    build(ls[o],l,mid); 
    rs[o]=++ko;
    build(rs[o],mid+1,r);
    t[o][0][0]=t[o][1][0]=0;
    t[o][0][1]=t[o][1][1]=U;
}
 
inline void updata(int o)
{
    int le=ls[o],ri=rs[o];
    t[o][0][0]=((t[le][0][0]^U)&t[ri][0][0])^((t[le][0][0]&t[ri][0][1]));
    t[o][0][1]=((t[le][0][1]^U)&t[ri][0][0])^((t[le][0][1]&t[ri][0][1]));
    t[o][1][0]=((t[ri][1][0]^U)&t[le][1][0])^((t[ri][1][0]&t[le][1][1]));
    t[o][1][1]=((t[ri][1][1]^U)&t[le][1][0])^((t[ri][1][1]&t[le][1][1]));
}
 
inline void cor(int o,int l,int r,int po,kk a,int b)
{
    if(l==r){
         
        if(b==1)t[o][0][0]=0,t[o][0][1]=a;
        if(b==2)t[o][0][0]=a,t[o][0][1]=U;
        if(b==3)t[o][0][0]=a,t[o][0][1]=U^a;
         
        if(b==1)t[o][1][0]=0,t[o][1][1]=a;
        if(b==2)t[o][1][0]=a,t[o][1][1]=U;
        if(b==3)t[o][1][0]=a,t[o][1][1]=U^a;
         
        return;
    }
    int mid=l+r>>1;
    if(po<=mid)cor(ls[o],l,mid,po,a,b);
    else cor(rs[o],mid+1,r,po,a,b);
    updata(o);
}
 
inline void ask1(int o,int l,int r,int le,int ri)
{
    if(l==le&&r==ri){
        t0=((t0^U)&t[o][0][0])^(t0&t[o][0][1]);
        t1=((t1^U)&t[o][0][0])^(t1&t[o][0][1]);
        return;
    }
    int mid=l+r>>1;
    if(ri<=mid)ask1(ls[o],l,mid,le,ri);
    else if(le>mid)ask1(rs[o],mid+1,r,le,ri);
    else {
        ask1(ls[o],l,mid,le,mid);
        ask1(rs[o],mid+1,r,mid+1,ri);
    }
} 
  
inline void ask2(int o,int l,int r,int le,int ri)
{
    if(l==le&&r==ri){
        t0=((t0^U)&t[o][1][0])^(t0&t[o][1][1]);
        t1=((t1^U)&t[o][1][0])^(t1&t[o][1][1]);
        return;
    }
    int mid=l+r>>1;
    if(ri<=mid)ask2(ls[o],l,mid,le,ri);
    else if(le>mid)ask2(rs[o],mid+1,r,le,ri);
    else {
        ask2(rs[o],mid+1,r,mid+1,ri);
        ask2(ls[o],l,mid,le,mid);
    }
}
 
inline int lca(int x,int y)
{
    if(dep[y]<dep[x])swap(x,y);
    for(int l=19;l>=0;--l)if(dep[f[y][l]]>=dep[x])y=f[y][l];
    for(int l=19;l>=0;--l)if(f[x][l]!=f[y][l])x=f[x][l],y=f[y][l];
    return (x!=y)?(fa[x]):x;
}
 
inline kk ques(ll sj,int x,int y)
{
    int z=lca(x,y);
    t0=0,t1=U;
    while(dep[gf[x]]>=dep[z]){
        ask2(gf[x],1,len[x],1,pp[x]);
        x=fa[gf[x]];
    }
    if(dep[x]>=dep[z])ask2(gf[x],1,len[x],pp[z],pp[x]);
    int e=0;
    while(dep[gf[y]]>dep[z]){
        ++e;
        yy[e][0]=gf[y];
        yy[e][1]=1; yy[e][2]=pp[y];
        y=fa[gf[y]];
    }
    if(dep[y]>dep[z]){
        ++e;
        yy[e][0]=gf[y];
        yy[e][1]=pp[z]+1;
        yy[e][2]=pp[y];
    }
    fd(i,e,1)ask1(yy[i][0],1,len[yy[i][0]],yy[i][1],yy[i][2]);
    kk sx=0,ans=0;
    kk dd=(kk)1<<63;
    fo(i,1,64){
        kk k1=0,k2=0;
        if((sx|dd)<=sj)k1=t1&dd;
        k2=t0&dd;
        if(k2>=k1)ans=ans|k2; 
        else ans|=k1,sx|=dd;
        dd>>=1;
    }
    return ans;
}
 
int main()
{
    int useless;
    scanf("%d%d%d",&n,&m,&useless);
    fo(i,1,n)fh[i]=read(),bq[i]=_read();
    fo(i,1,n-1)x=read(),y=read(),llb(x,y),llb(y,x);
    ko=n;
    fa[1]=-1; gf[1]=dep[1]=1;
    dg(1); dep[1]=1; dfs(1); fa[1]=0;
    fo(i,1,n)if(gf[i]==i)build(i,1,len[i]);
    fo(i,1,n)len[i]=len[gf[i]],pp[i]=dep[i]-dep[gf[i]]+1;
    fo(i,1,n)cor(gf[i],1,len[i],pp[i],bq[i],fh[i]);
    fo(i,1,m){
        int op=read();
        if(op==2){
            x=read();
            fh[x]=read();
            bq[x]=_read();
            cor(gf[x],1,len[x],pp[x],bq[x],fh[x]);
        }
        if(op==1){
            x=read(); y=read();
            kk z=_read();
            kk ans=ques(z,x,y);
            printf("%llu\n",ans);
        }
    }
}

你可能感兴趣的:(线段树,树链剖分)