[spoj COT2]树上莫队

Posted ACMsong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[spoj COT2]树上莫队相关的知识,希望对你有一定的参考价值。

题目链接:http://www.spoj.com/problems/COT2/

学会了树上莫队,真的是太激动了!参照博客:http://codeforces.com/blog/entry/43230 讲的十分清楚。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=40005;
const int maxm=100005;

int cur;
int sat[MAXN];
int ean[MAXN];
int A[MAXN*2];
int a[MAXN];
int cou[MAXN];
int vis[MAXN];

int block_size;

struct Query
{
    int id;
    int l,r;
    int ex;
    bool operator < (const Query& q) const
    {
        int b1=(l-1)/block_size;
        int b2=(q.l-1)/block_size;
        return b1<b2 || b1==b2 && r<q.r;
    }
} query[maxm];
int ans[maxm];

int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
    int mm[2*MAXN];
    int dp[2*MAXN][20];//最小值对应的下标
    void init(int n)
    {
        mm[0] = -1;
        for(int i = 1; i <= n; i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= mm[n]; j++)
            for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] <
                           rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)//查询[a,b]之间最小值的下标
    {
        if(a > b)swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <=
               rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
};
//边的结构体定义
struct Edge
{
    int to,next;
};
Edge edge[MAXN*2];
int tot,head[MAXN];
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
int cnt;
ST st;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)//加边,无向边需要加两次
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{
    sat[u]=++cur;
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre)continue;
        dfs(v,u,dep+1);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
    ean[u]=++cur;
}
void LCA_init(int root,int node_num)//查询LCA前的初始化
{
    cnt = 0;
    dfs(root,root,0);
    st.init(2*node_num-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
    return F[st.query(P[u],P[v])];
}

vector<int> ls;
int nowL,nowR,nowAns;

void inc(int i)  // add or remove a[i]
{
    if (vis[i])
    {
        cou[a[i]]--;
        vis[i]^=1;
        if (cou[a[i]]==0) nowAns--;
    }
    else
    {
        cou[a[i]]++;
        vis[i]^=1;
        if (cou[a[i]]==1) nowAns++;
    }
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    for (int i=1; i<=n; i++) ls.push_back(a[i]);
    sort(ls.begin(),ls.end());
    ls.erase(unique(ls.begin(),ls.end()),ls.end());
    for (int i=1; i<=n; i++) a[i]=lower_bound(ls.begin(),ls.end(),a[i])-ls.begin()+1;
    init();
    for(int i = 1; i < n; i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    LCA_init(1,n);
    for (int i=1; i<=n; i++) A[sat[i]]=i;
    for (int i=1; i<=n; i++) A[ean[i]]=i;
    block_size=(int)sqrt(cur)+1;
    for (int i=1; i<=m; i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if (sat[u]>sat[v]) swap(u,v);
        int lc=query_lca(u,v);
        if (lc==u)
        {
            query[i].l=sat[u];
            query[i].r=sat[v];
            query[i].ex=-1;
            query[i].id=i;
        }
        else
        {
            query[i].l=ean[u];
            query[i].r=sat[v];
            query[i].ex=sat[lc];
            query[i].id=i;
        }
    }
    sort(query+1,query+1+m);
    for (int i=1; i<=m; i++)
    {
        while (nowR<query[i].r)
        {
            nowR++;
            inc(A[nowR]);
        }
        while (nowL>query[i].l)
        {
            nowL--;
            inc(A[nowL]);
        }
        while (nowR>query[i].r)
        {
            inc(A[nowR]);
            nowR--;
        }
        while (nowL<query[i].l)
        {
            if (nowL) inc(A[nowL]);
            nowL++;
        }
        if (query[i].ex!=-1) inc(A[query[i].ex]);
        ans[query[i].id]=nowAns;
        if (query[i].ex!=-1) inc(A[query[i].ex]);
    }
    for (int i=1; i<=m; i++) printf("%d\n",ans[i]);
    return 0;
}

 

以上是关于[spoj COT2]树上莫队的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ.COT2 Count on a tree II(树上莫队)

SPOJ COT2 - Count on a tree II(树上莫队)

SPOJ - COT2

SPOJ10707COT2 - Count on a tree II

学术篇SPOJ COT 树上主席树

SPOJ - COT2 离线路径统计