【HDU4897】Little Devil I-树链剖分

测试地址:Little Devil I
题目大意:有一棵树,每条边一开始为白色,维护两个操作:将路径上所有的边反色(黑白互换),将所有和路径相邻(只有一个端点在路径上)的边反色,并支持询问一条路径上黑色边的数目。
做法:本题需要用到树链剖分。
首先路径反色很模板,就不说了。关键是路径相邻边反色,看上去很不可做,因此我们考虑等价代换。
注意到,一条边只有一个端点在路径上时,它才会被反色,有零个或两个端点的边不受影响,这看上去就非常的像异或了。于是我们可以给路径上每个点打上标记,一条边只有在两个端点的标记总数为奇数时,才表示它在这种情况下被反色。那么在询问时,重链上的边显然可以合并出来(注意要和路径反色的标记一起考虑),而轻边不超过logn条,在线段树中分别询问这两个点的标记进行处理即可。
于是我们就解决了这一题,时间复杂度为O(nlog2n)
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int T,n,m,tot,first[100010];
int fa[100010]={0},dep[100010]={0},siz[100010]={0};
int son[100010]={0},top[100010],pos[100010],tim;
bool tag[400010][2],cntl[400010][2],cntr[400010];
int ans[400010];
struct edge
{
    int v,next;
}e[200010];
bool flag,lastr;

void insert(int a,int b)
{
    e[++tot].v=b;
    e[tot].next=first[a];
    first[a]=tot;
}

void dfs1(int v)
{
    dep[v]=dep[fa[v]]+1;
    siz[v]=1,son[v]=0;
    for(int i=first[v];i;i=e[i].next)
        if (e[i].v!=fa[v])
        {
            fa[e[i].v]=v;
            dfs1(e[i].v);
            siz[v]+=siz[e[i].v];
            if (siz[e[i].v]>siz[son[v]])
                son[v]=e[i].v;
        }
}

void dfs2(int v,int t)
{
    top[v]=t,pos[v]=++tim;
    if (son[v]) dfs2(son[v],t);
    for(int i=first[v];i;i=e[i].next)
        if (e[i].v!=fa[v]&&e[i].v!=son[v])
            dfs2(e[i].v,e[i].v);
}

void update(int no,int l,int r,bool op)
{
    tag[no][op]=!tag[no][op];
    if (!op) cntl[no][0]=!cntl[no][0];
    else cntl[no][1]=!cntl[no][1],cntr[no]=!cntr[no];
    if (!op) ans[no]=r-l-ans[no];
}

void pushdown(int no,int l,int r)
{
    int mid=(l+r)>>1;
    if (tag[no][0])
    {
        update(no<<1,l,mid,0);
        update(no<<1|1,mid+1,r,0);
    }
    if (tag[no][1])
    {
        update(no<<1,l,mid,1);
        update(no<<1|1,mid+1,r,1);
    }
    tag[no][0]=tag[no][1]=0;
}

void pushup(int no)
{
    ans[no]=ans[no<<1]+ans[no<<1|1];
    cntl[no][0]=cntl[no<<1][0];
    cntl[no][1]=cntl[no<<1][1];
    cntr[no]=cntr[no<<1|1];
    if (cntl[no<<1|1][1]^cntr[no<<1]^cntl[no<<1|1][0])
        ans[no]++;
}

void segmodify(int no,int l,int r,int s,int t,bool op)
{
    if (l>=s&&r<=t)
    {
        update(no,l,r,op);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(no,l,r);
    if (s<=mid) segmodify(no<<1,l,mid,s,t,op);
    if (t>mid) segmodify(no<<1|1,mid+1,r,s,t,op);
    pushup(no);
}

int segquery(int no,int l,int r,int s,int t)
{
    if (l>=s&&r<=t)
    {
        bool right=0;
        if (flag)
        {
            right^=cntl[no][0]^cntl[no][1];
            right^=lastr;
        }
        else flag=1;
        lastr=cntr[no];
        return ans[no]+(int)right;
    }
    int totans=0,mid=(l+r)>>1;
    pushdown(no,l,r);
    if (s<=mid) totans+=segquery(no<<1,l,mid,s,t);
    if (t>mid) totans+=segquery(no<<1|1,mid+1,r,s,t);
    return totans;
}

bool querypoint(int no,int l,int r,int x,int op)
{
    if (l==r)
    {
        if (op==0) return cntl[no][0];
        if (op==1) return cntl[no][1];
        if (op==2) return cntr[no];
    }
    int mid=(l+r)>>1;
    pushdown(no,l,r);
    if (x<=mid) return querypoint(no<<1,l,mid,x,op);
    else return querypoint(no<<1|1,mid+1,r,x,op);
}

void modify(int a,int b,bool op)
{
    while(top[a]!=top[b])
    {
        if (dep[top[a]]<dep[top[b]])
            swap(a,b);
        segmodify(1,1,n,pos[top[a]],pos[a],op);
        a=fa[top[a]];
    }
    if (dep[a]>dep[b]) swap(a,b);
    if (!op&&a==b) return;
    if (!op) segmodify(1,1,n,pos[a]+1,pos[b],op);
    else segmodify(1,1,n,pos[a],pos[b],op);
}

int query(int a,int b)
{
    int totans=0;
    while(top[a]!=top[b])
    {
        if (dep[top[a]]<dep[top[b]])
            swap(a,b);
        flag=0;
        totans+=segquery(1,1,n,pos[top[a]],pos[a]);
        bool right=0;
        right^=querypoint(1,1,n,pos[top[a]],0);
        right^=querypoint(1,1,n,pos[top[a]],1);
        right^=querypoint(1,1,n,pos[fa[top[a]]],2);
        if (right) totans++;
        a=fa[top[a]];
    }
    if (dep[a]>dep[b]) swap(a,b);
    flag=0;
    totans+=segquery(1,1,n,pos[a],pos[b]);
    return totans;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(first,0,sizeof(first));
        tot=0;

        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(a,b),insert(b,a);
        }

        dfs1(1);
        tim=0;
        dfs2(1,1);

        memset(tag,0,sizeof(tag));
        memset(cntl,0,sizeof(cntl));
        memset(cntr,0,sizeof(cntr));
        memset(ans,0,sizeof(ans));
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if (op<=2) modify(x,y,op-1);
            else printf("%d\n",query(x,y));
        }
    }

    return 0;
}
posted @ 2018-09-02 21:25  Maxwei_wzj  阅读(196)  评论(0编辑  收藏  举报