树上莫队

听说树上莫队只能搞子树询问?

http://codeforces.com/blog/entry/43230

这篇运用了一个奇技淫巧把它扩展到了路径询问。现在主要就解(fan)释(yi)一下那篇博客。

A. 子树树上莫队

现在有一棵树,有n个节点,节点有点权,每次询问一个子树内的不重复数个数。

1<=n,q<=10^5,1<=点权<=10^9。

这个题显然比较trivial嘛...先把点权离散一下,然后一遍dfs搞出dfs序,那么一个子树就对应dfs序上一段,所以我们就可以在dfs序上莫队,开一个数组记一下每个数的出现次数。

B. 路径树上莫队

现在有一棵树,有n个节点,节点有点权,每次询问一条路径上的不重复数个数。

1<=n,q<=10^5,1<=点权<=10^9。

莫队用不了了?我们重新定义一个dfs序!

我们在开始访问和结束访问一个点的时候都记一下时间戳,我们设开始访问的时间为st,结束访问的时间为ed。

我们假设要询问一条路径a-b,设lca为p=lca(a,b)。不妨设st[a]<=st[b](否则交换一下)。

当p=a时,这应该是一个比较简单的情形:a-b是一段父子链。

我们考虑这个新dfs序上[st[a],st[b]]的点,我们可以发现,a-b上的点被算了一遍,其他点都被算了2遍或0遍!那么我们统计的时候注意一下就可以了。

当p≠a时,我们也要一样统计[ed[a],st[b]]的点(从ed[a]开始为保证a不会被排除掉),但是这回lca会被重复统计,所以要另外算一下。

这题就是spoj上的COT2~

(其实并不是很好写啊qaq)

//By zzq
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <set>
#include <map>
using namespace std;
#define SZ 666666
#define P 20
int n,m,a[SZ],fst[SZ],vb[SZ],nxt[SZ],as[SZ],M=0,fa[SZ];
void ad_de(int a,int b) {++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b;}
void adde(int a,int b) {ad_de(a,b); ad_de(b,a);}
int cc=0,st[SZ],ed[SZ],dfx[SZ];
void dfs(int x)
{
    st[x]=++cc; dfx[cc]=x;
    for(int e=fst[x];e;e=nxt[e])
    {
        int b=vb[e]; if(b==fa[x]) continue;
        fa[b]=x; dfs(b);
    }
    ed[x]=++cc; dfx[cc]=x;
}
typedef pair<int,int> pii;
int cc_=0,app[SZ],dep[SZ],lo2[SZ];
pii pp[SZ],minn[SZ][P];
void dfs_(int x)
{
    ++cc_; app[x]=cc_; pp[cc_]=pii(dep[x],x);
    for(int e=fst[x];e;e=nxt[e])
    {
        int b=vb[e]; if(b==fa[x]) continue;
        dep[b]=dep[x]+1; dfs_(b);
        pp[++cc_]=pii(dep[x],x);
    }
}
void build()
{
    for(int i=1;i<=cc_;i++) minn[i][0]=pp[i];
    for(int i=1;i<=cc_;i++)
    {
        int g=0;
        while((1<<g)<=i) ++g;
        lo2[i]=g-1;
    }
    for(int p=1;p<P;p++)
    {
        for(int i=1;i<=cc_;i++)
        {
            if(i+(1<<p)-1>cc_) break;
            minn[i][p]=min(minn[i][p-1],minn[i+(1<<(p-1))][p-1]);
        }
    }
}
int lca(int a,int b)
{
    a=app[a]; b=app[b];
    if(a>b) swap(a,b);
    int l2=lo2[b-a+1];
    return min(minn[a][l2],minn[b-(1<<l2)+1][l2]).second;
}
int bs,qn=0;
struct query {int l,r,m,id;} qs[SZ];
bool operator < (query a,query b)
{
    if(a.l/bs!=b.l/bs) return a.l/bs<b.l/bs;
    else return a.r<b.r;
}
#define Addq(l_,r_,m_,id_) ++qn, qs[qn].l=l_, qs[qn].r=r_, qs[qn].m=m_, qs[qn].id=id_;
int cov[SZ],coa[SZ];
int ans=0,anss[SZ];
void edt(int p,int k)
{
    ans-=(bool)coa[a[p]];
    coa[a[p]]-=cov[p]&1;
    cov[p]+=k;
    coa[a[p]]+=cov[p]&1;
    ans+=(bool)coa[a[p]];
}
int main()
{
    scanf("%d%d",&n,&m); bs=sqrt(n)+1;
    for(int i=1;i<=n;i++) scanf("%d",a+i), as[i]=a[i];
    sort(as+1,as+1+n); int nn=unique(as+1,as+1+n)-as-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(as+1,as+1+nn,a[i])-as;
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        adde(a,b);
    }
    dfs(1); dfs_(1); build();
    for(int i=1;i<=m;i++)
    {
        int a,b,p;
        scanf("%d%d",&a,&b);
        p=lca(a,b);
        if(st[a]>st[b]) swap(a,b);
        if(p==a) Addq(st[a],st[b],0,i)
        else Addq(ed[a],st[b],p,i)
    }
    sort(qs+1,qs+1+qn);
    int l=1,r=0;
    for(int i=1;i<=qn;i++)
    {
        int ql=qs[i].l,qr=qs[i].r;
        while(l<ql) edt(dfx[l++],-1);
        while(l>ql) edt(dfx[--l],1);
        while(r>qr) edt(dfx[r--],-1);
        while(r<qr) edt(dfx[++r],1);
        if(qs[i].m) edt(qs[i].m,1);
        anss[qs[i].id]=ans;
        if(qs[i].m) edt(qs[i].m,-1);
    }
    for(int i=1;i<=m;i++) printf("%d\n",anss[i]);
}
posted @ 2016-06-29 17:32  fjzzq2002  阅读(2662)  评论(2编辑  收藏  举报