樹上莫隊


聽說樹上莫隊只能搞子樹詢問?

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]);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM