bzoj4811[Ynoi2017]由乃的OJ

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4811

第一次写树链剖分。搞清楚原树的点和线段树上的点的对应关系很重要。

  (树链剖分之所以能对应到线段树上,是因为走的不是重链就是点,都是dfs序连续区间。)

本题有64位,不用像“睡觉困难综合征”那样每一位循环,弄到unsigned long long里就能一起弄。

  注意一下合并,想想就能明白。还要注意方向。

感觉是一道很好的模板题。抄了TJ的代码,觉得写得好好。(https://blog.csdn.net/a1799342217/article/details/78818480)

#include<iostream>
#include<cstdio>
#include<cstring>
#define ull unsigned long long
using namespace std;
const int N=1e5+5;
int n,m,lm,head[N],xnt,tot,top[N],fa[N],dep[N],id[N],rnk[N],son[N],siz[N];
ull op[N][2];
struct Dt{
    ull p0,p1;//都是ull! 
};
struct Edge{
    int next,to;
    Edge(int n=0,int t=0):next(n),to(t) {}
}edge[N<<1];
struct Node{
    int l,r,ls,rs;
    Dt fr,fl;
}a[N<<1];
void added(int x,int y)
{
    edge[++xnt]=Edge(head[x],y);head[x]=xnt;
    edge[++xnt]=Edge(head[y],x);head[y]=xnt;
}
void dfs1(int cr,int depth)
{
    dep[cr]=depth;siz[cr]=1;
    for(int i=head[cr],v;i;i=edge[i].next)
        if((v=edge[i].to)!=fa[cr])
        {
            fa[v]=cr;dfs1(v,depth+1);siz[cr]+=siz[v];
            if(siz[v]>siz[son[cr]])son[cr]=v;
        }
}
void dfs2(int cr)
{
    id[cr]=++tot;rnk[tot]=cr;
    if(!son[cr])return;
    top[son[cr]]=top[cr],dfs2(son[cr]);
    for(int i=head[cr],v;i;i=edge[i].next)
        if((v=edge[i].to)!=son[cr]&&v!=fa[cr])
        {
            top[v]=v;dfs2(v);
        }
}
Dt updt(ull op,ull w)
{
    Dt ret;
    if(op==1)ret.p0=0&w,ret.p1=(~0)&w;
    if(op==2)ret.p0=0|w,ret.p1=(~0)|w;
    if(op==3)ret.p0=0^w,ret.p1=(~0)^w;
    return ret;
}
Dt pshp(Dt x,Dt y)
{
    Dt ret;
    ret.p0=(x.p0&y.p1)|(~x.p0&y.p0);
    ret.p1=(x.p1&y.p1)|(~x.p1&y.p0);
    return ret;
}
void build(int l,int r,int cr)
{
    a[cr].l=l;a[cr].r=r;
    if(l==r){a[cr].fl=a[cr].fr=updt(op[rnk[l]][0],op[rnk[l]][1]);return;}//rnk[l]!
    int mid=l+r>>1;
    tot++;a[cr].ls=tot;
    build(l,mid,tot);
    tot++;a[cr].rs=tot;
    build(mid+1,r,tot);
    a[cr].fl=pshp(a[a[cr].ls].fl,a[a[cr].rs].fl);
    a[cr].fr=pshp(a[a[cr].rs].fr,a[a[cr].ls].fr);
}
void mdfy(int cr,int x,ull op,ull w)
{
    if(a[cr].l==a[cr].r)
    {
        a[cr].fl=a[cr].fr=updt(op,w);return;
    }
    int mid=a[cr].l+a[cr].r>>1;
    if(x<=mid)mdfy(a[cr].ls,x,op,w);
    else mdfy(a[cr].rs,x,op,w);
    a[cr].fl=pshp(a[a[cr].ls].fl,a[a[cr].rs].fl);
    a[cr].fr=pshp(a[a[cr].rs].fr,a[a[cr].ls].fr);
}
Dt srch(int cr,int l,int r,int fx)
{
    if(a[cr].l>=l&&a[cr].r<=r)
        if(fx)return a[cr].fr;
        else return a[cr].fl;
    int mid=a[cr].l+a[cr].r>>1;//a[cr].l a[cr].r  !l !r
    if(mid>=r)return srch(a[cr].ls,l,r,fx);
    else if(mid<l)return srch(a[cr].rs,l,r,fx);
    else return pshp(srch(fx?a[cr].rs:a[cr].ls,l,r,fx),srch(fx?a[cr].ls:a[cr].rs,l,r,fx));
}
Dt find(int x,int y)
{
    Dt ans1=updt(3,0),ans2=updt(3,0);
    while(top[x]!=top[y])
        if(dep[top[x]]>dep[top[y]])
        {
            ans1=pshp(ans1,srch(1,id[top[x]],id[x],1));//1(区间是从上到下,故从右可接上当前)
            x=fa[top[x]];
        }
        else
        {
            ans2=pshp(srch(1,id[top[y]],id[y],0),ans2);
            y=fa[top[y]];
        }
    if(dep[x]<=dep[y])return pshp(pshp(ans1,srch(1,id[x],id[y],0)),ans2);
    else return pshp(pshp(ans1,srch(1,id[y],id[x],1)),ans2);//1
}
void query(int x,int y,ull z)
{
    Dt ans=find(x,y);ull ret=0,sum=0;
    for(int i=lm-1;i>=0;i--)
        if((1ull<<i)&ans.p0)ret|=(1ull<<i);
        else if(((1ull<<i)&ans.p1)&&(sum|(1ull<<i))<=z)
            sum|=(1ull<<i),ret|=(1ull<<i);
    printf("%llu\n",ret);
}
int main()
{
    scanf("%d%d%d",&n,&m,&lm);
    for(int i=1;i<=n;i++)scanf("%llu%llu",&op[i][0],&op[i][1]);
    int x,y;
    for(int i=1;i<n;i++)scanf("%d%d",&x,&y),added(x,y);
    dfs1(1,1);top[1]=1;dfs2(1);tot=1;build(1,n,1);
    ull z;int q;
    while(m--)
    {
        scanf("%d%d%d%llu",&q,&x,&y,&z);
        if(q==2)mdfy(1,id[x],y,z);/////id[x]
        else query(x,y,z);
    }
    return 0;
}

 

posted on 2018-06-12 08:39  Narh  阅读(398)  评论(0编辑  收藏  举报

导航