COT2

博客已经好久不更新了。
一来是身体差,二来也是没有人看。
再者说自己也比较懒
然后兴致勃勃跑去直接写了个二维bit……
后来觉得不过瘾就去写了个树上莫队QAQ
然后……
因为自己纸张调了一下午。
TAT
其实还是很好懂的,随便找找就能找到资料。

#include <bits/stdc++.h>
#define Rep(i,n) for(int i = 1;i <= n;++ i)
#define v edge[i].to
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
using namespace std;
const int N = 100001;
struct Edge{int next,to;}edge[N << 1];
int B,n,m,rt,cnt,head[N],tim,dfn[N],sz[N],ans,bel[N],dep[N],Ans[N],fa[N],son[N],top[N],stk[N],tot,Top,cur[N];
int col[N];
bool vis[N];
struct Query{int x,y,id;}q[N];
bool cmp(Query a,Query b){return bel[a.x] == bel[b.x] ? dfn[a.y] < dfn[b.y] : bel[a.x] < bel[b.x];}
void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
int dfs(int x)
{
    int siz = 0;
    sz[x] = 1;dfn[x] = ++ tim;
    RepG(i,x)
        if(v != fa[x])
        {
            fa[v] = x;
            dep[v] = dep[x] + 1;
            siz += dfs(v);
            sz[x] += sz[v];
            if(sz[son[x]] < sz[v])
                son[x] = v;
            if(siz >= B)
            {
                tot ++;
                for(int j = 1;j <= siz;++ j)bel[stk[Top --]] = tot;
                siz = 0;
            }
        }
    stk[++ Top] = x;
    return siz + 1;
}
void dfs(int x,int tp)
{
    top[x] = tp;
    if(!son[x])return;
    dfs(son[x],tp);
    RepG(i,x)if(v != fa[x] && v != son[x])dfs(v,v);
}
int LCA(int x,int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
void Rev(int x)
{
    vis[x] ^= 1;
    if(vis[x])cur[col[x]] ++,ans += (cur[col[x]] == 1);
    else cur[col[x]] --,ans -= (!cur[col[x]]);
}
void Move(int x,int y)
{
    int z = LCA(x,y);
    while(x != z)Rev(x),x = fa[x];
    while(y != z)Rev(y),y = fa[y];
}
int b[N];
int Bin(int x)
{
    int l = 1,r = n,mid;
    while(l < r)
    {
        mid = l + r >> 1;
        if(b[mid] < x)l = mid + 1;
        else r = mid;
    }
    return l;
}
int main()
{
//  freopen("data.in","r",stdin);
//  freopen("out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    B = (int)sqrt(n);
    Rep(i,n)scanf("%d",&col[i]),b[i] = col[i];
    sort(b + 1,b + 1 + n);
    Rep(i,n)col[i] = Bin(col[i]);
    for(int i = 1,x,y;i < n;++ i)
    {
        scanf("%d%d",&x,&y);
        save(x,y),save(y,x);
    }
    rt = 1;
    int re = dfs(rt);dfs(rt,rt);
    Rep(i,re)bel[stk[Top --]] = tot;
    Rep(i,m)
    {
        scanf("%d%d",&q[i].x,&q[i].y),q[i].id = i;
        if(bel[q[i].x] > bel[q[i].y])swap(q[i].x,q[i].y);
    }
    sort(q + 1,q + 1 + m,cmp);
    int lca,x,y;
    x = y = 1;
    for(int i = 1;i <= m;++ i)
    {
        Move(q[i].x,x);
        Move(q[i].y,y);
        x = q[i].x,y = q[i].y;
        lca = LCA(x,y);
        Rev(lca);
        Ans[q[i].id] = ans;
        Rev(lca);
    }
    Rep(i,m)printf("%d\n",Ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值