BZOJ2819/Nim

Posted on By 二价氢

首先,我们求出树的DFS序(为何是树?要解释?!)

下面说明算法

例:

这棵树的DFS序应该是ABEEFFBCCDGHHIIJJGDA

根据这来建立BIT,显然两个点的最近公共祖先就在这两个点之外某处

如,E到H的路径为:EBADGH

DFS序则为EFFBCCDGH,所有在这个路径上的点都出现一次(LCA除外),所有不在这个路径上的点都出现了0或2次

根据Nim博弈的性质,我们只需要求出对应的区间异或和再异或LCA的值,就能得到答案

居然花了16秒的AC-Code(什么时候我的常数才能小下去?)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <utility>
#include <vector>
using namespace std;
const int MAXN=500005,MAXM=1000005;
//--Tree
int t[MAXM],next[MAXM],first[MAXN],tote;
int A[MAXN],C[MAXM];
int stack[MAXN],tot;
int begin[MAXN],end[MAXN];
int deep[MAXN];
int anc[MAXN][20];
int n;
//--DFS
void dfs(int s)
{
    int x,f,top=0;
    begin[stack[++top]=s]=deep[s]=++tot;
    while (top)
    {
        x=stack[top];f=0;
        for (int i=first[x];i;i=next[i])
        {
            if (!begin[t[i]])
            {
                begin[t[i]]=++tot;
                anc[t[i]][0]=x;
                deep[t[i]]=deep[x]+1;
                stack[++top]=t[i];
                first[x]=next[i];
                f=1;
                break;
            }
        }
        if (!f)
        {
            end[x]=++tot;
            top--;
        }
    }
}
void ae(int u,int v)
{
    tote++;
    t[tote]=v;next[tote]=first[u];first[u]=tote;
    tote++;
    t[tote]=u;next[tote]=first[v];first[v]=tote;
}
int lca(int x,int y)
{
    if (deep[x]<deep[y])
        swap(x,y);
    int k=deep[x]-deep[y],j=0;
    while (k)
    {
        if (k&1)
            x=anc[x][j];
        j++;k>>=1;
    }
    if (x==y)
        return x;
    for (int j=19;j>=0;j--)
        if (anc[x][j]!=anc[y][j])
        {
            x=anc[x][j];
            y=anc[y][j];
        }
    return anc[x][0];
}
//--Work
int lowbit(int x)
{
    return x&(-x);
}
void edit(int i)
{
    for (int x=begin[i];x<MAXM;x+=lowbit(x))
        C[x]^=A[i];
    for (int x=end[i];x<MAXM;x+=lowbit(x))
        C[x]^=A[i];
}
int query(int i)
{
    int ret=0;
    for (int x=i;x;x-=lowbit(x))
        ret^=C[x];
    return ret;
}
int main()
{
    int tu,tv;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&tu,&tv);
        ae(tu,tv);
    }
    dfs(1);
    for (int i=1;i<=n;i++)
        edit(i);
    for (int j=1;j<20;j++)
        for (int i=1;i<=n;i++)
            anc[i][j]=anc[anc[i][j-1]][j-1];
    char buf[20];
    int m,qa,qb;
    scanf("%d",&m);
    while (m--)
    {
        scanf("%s%d%d",buf,&qa,&qb);
        if (buf[0]=='Q')
        {
            if (query(begin[qa])^query(begin[qb])^A[lca(qa,qb)])
                printf("Yes\n");
            else
                printf("No\n");
        }else
        {
            edit(qa);
            A[qa]=qb;
            edit(qa);
        }
    }
    return 0;
}