【试炼场】软件包管理器 【树链剖分】

传送门

题目大意

一颗树,N个点,初始标记均为0,两个操作:
①查询某个点到根的路径上0的个数,并全部变为1
②查询某个点子树里1的个数,并全部变成0

题解

emm我不知道说什么。
①=链查询+链覆盖,②=子树查询+子树覆盖
直接上代码吧。只是为了发篇博客2333
(我觉得等我写了树链剖分的详解之后该把这个删了。。这种模板没什么好解析的)

#include
#define rint register int
#define endll '\n'
#define ivoid inline void
#define iint inline int
#define ll long long
using namespace std;
const int N=1e6+5;
const int M=3e3+5;
const int inf=0x3f3f3f3f;
int n,m,a,b,k,x,y,s,t,u,v,w,l,r,ql,qr,q;
int deep[N],top[N],id[N],rank[N],son[N],size[N],head[N],fa[N],col[N];
int cnt=1,sum,ans,pos1,pos2,pos3,change,rt;
char c[8],c1;
struct Edge{int v,next;}edge[N<<1];
struct Node{int val,tag;}node[N<<4];

iint rad()
{
    int x=0,f=1;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
ivoid addedge(int u,int v){edge[++cnt].v=v,edge[cnt].next=head[u],head[u]=cnt;}

ivoid dfs1(int now)
{
    size[now]=1;
    for(rint i=head[now];i;i=edge[i].next){
        int d=edge[i].v;
        if(d==fa[now])continue;
        fa[d]=now,deep[d]=deep[now]+1,dfs1(d);
        if(size[d]>size[son[now]])son[now]=d;
        size[now]+=size[d];
    }
}

ivoid dfs2(int now,int op)
{
    id[now]=++cnt;rank[cnt]=now;top[now]=op;
    if(!son[now])return;dfs2(son[now],op);
    for(rint i=head[now];i;i=edge[i].next){
        int d=edge[i].v;
        if(d==fa[now]||d==son[now])continue;
        dfs2(d,d);
    }
}

ivoid pushup(int n)
{
    int lson=n<<1,rson=(n<<1)|1;
    node[n].val=node[lson].val+node[rson].val;
}

ivoid pushdown(int l,int r,int n)
{
    if(node[n].tag==0)return;
    int lson=n<<1,rson=(n<<1)|1,mid=(l+r)>>1;
    if(node[n].tag==1){
    	node[lson].val=mid-l+1;node[rson].val=r-mid;
        node[lson].tag=1,node[rson].tag=1;
    }
    if(node[n].tag==-1){
    	node[lson].val=node[rson].val=0;
    	node[lson].tag=node[rson].tag=-1;
    }
    node[n].tag=0;
}

ivoid build(int l,int r,int n)
{
    if(l==r){return;}
    int mid=(l+r)>>1;
    build(l,mid,n<<1);build(mid+1,r,(n<<1)|1);
    pushup(n);
}

ivoid changesome(int l,int r,int n,int ql,int qr)
{
    if(l>=ql&&r<=qr){
        node[n].val=(r-l+1);
        node[n].tag=1;
        return;
    }
    pushdown(l,r,n);
    int mid=(l+r)>>1;
    if(mid>=ql)changesome(l,mid,n<<1,ql,qr);
    if(mid<qr)changesome(mid+1,r,(n<<1)|1,ql,qr);
    pushup(n);
}

ivoid crashsome(int l,int r,int n,int ql,int qr)
{
    if(l>=ql&&r<=qr){
        node[n].val=0;
        node[n].tag=-1;
        return;
    }
    pushdown(l,r,n);
    int mid=(l+r)>>1;
    if(mid>=ql)crashsome(l,mid,n<<1,ql,qr);
    if(mid<qr)crashsome(mid+1,r,(n<<1)|1,ql,qr);
    pushup(n);
}

ivoid query(int l,int r,int n,int ql,int qr)
{
    if(l>=ql&&r<=qr){
        ans+=(r-l+1)-node[n].val;
        return;
    }
    pushdown(l,r,n);
    int mid=(l+r)>>1;
    if(mid>=ql)query(l,mid,n<<1,ql,qr);
    if(mid<qr)query(mid+1,r,(n<<1)|1,ql,qr);
    pushup(n);
}

ivoid Lca_query(int x,int y)
{
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        ql=id[top[x]],qr=id[x],query(1,n,1,ql,qr);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    ql=id[x],qr=id[y],query(1,n,1,ql,qr);
}

ivoid Lca_change(int x,int y)
{
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        ql=id[top[x]],qr=id[x],changesome(1,n,1,ql,qr);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    ql=id[x],qr=id[y],changesome(1,n,1,ql,qr);
}


int main()
{
    n=rad();
    for(rint i=1;i<n;i++)v=rad(),addedge(i+1,v+1),addedge(v+1,i+1);
    cnt=0;dfs1(1),dfs2(1,1),build(1,n,1);rt=1;
    m=rad(); 
    for(rint i=1;i<=m;i++){
        cin>>c,x=rad();ans=0;x++;
        if(c[0]=='i')Lca_query(x,rt),cout<<ans<<endll,Lca_change(x,rt);
        if(c[0]=='u')ql=id[x],qr=id[x]+size[x]-1,query(1,n,1,ql,qr),
		cout<<qr-ql+1-ans<<endll,crashsome(1,n,1,ql,qr);
    }
}

你可能感兴趣的:(试炼场,树链剖分)