SPOJ COT2 树上的莫队算法,树上区间查询

题意:n个节点形成的一棵树。每个节点有一个值。m次查询,求出(u,v)路径上出现了多少个不同的数。

树上的莫队算法,同样将树分成siz=sqrt(n)块,然后离线操作。先对树dfs一遍,每当子树节点个数num>=siz,就将这num个分成一块。读取所有的查询按左端点所在块排序。

重点在于怎么进行区间转移,对路径的lca特殊处理,参考博客http://blog.csdn.net/kuribohg/article/details/41458639  


用倍增法求lca单次要用logn复杂度,要跑3200ms。有个地方可以优化,就是知道了所有的查询,也就是事先知道了转移路径,可以用离线的方法求O(n)求出所有需要用到的lca,这个写起来比较麻烦,不过可以优化到1800ns。代码写的比较挫。。。。

logn求lca:3200+ms

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=4e4+10;
const int maxm=1e5+10;

int n,m, siz;
vector g[maxn];
int a[maxn], b[maxn], ans[maxm];
int tot[maxn], in[maxn];
int fa[maxn][20], dep[maxn];

struct Query
{
    int l, r, id;
    int st,ed;
    bool operator <(const Query& a) const
    {
        return st!=a.st? st=siz){ //子树大小>=sqrt(n),分成一块
                for(int i=0; ibel[q[i].r])
            swap(q[i].l, q[i].r);
        q[i].id=i;
        q[i].st=bel[q[i].l];
        q[i].ed=bel[q[i].r];
    }
    sort(q, q+m);
}

int lca(int u, int v)
{
    if(dep[u]>dep[v]) swap(u, v);
    for(int i=0; i<20; i++)
        if((dep[v]-dep[u])>>i&1)
            v=fa[v][i];

    if(u==v) return u;
    for(int i=19; i>=0; i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];
}

void solve()
{
    int res=0;
    int cu=1, cv=1;

    for(int i=0; i


离线查询lca:1800+ms

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef pair P;
#define fir first
#define sec second
const int maxn=4e4+10;
const int maxm=1e5+10;

int n,m, siz;
vector g[maxn];
int first[maxn],ltot=0, nxt[6*maxm];
P lq[6*maxm];//所有需要查询的lca,lq[i].first保存v,second保存查询的id

int a[maxn], b[maxn], ans[maxm];
int tot[maxn], in[maxn], fa1[maxn];
int fa[maxn], lca[3*maxm], col[maxn];
int bel[maxn],st[maxn],top=0;
struct Query
{
    int l, r, id;
    int st,ed;
    bool operator <(const Query& a) const
    {
        return st!=a.st? st=siz){
            for(int i=0; ibel[q[i].r])
            swap(q[i].l, q[i].r);
        q[i].id=i;
        q[i].st=bel[q[i].l];
        q[i].ed=bel[q[i].r];
    }
    sort(q, q+m);

    cnt=0; ltot=0;
    memset(first, -1, sizeof(first));
    add(1, q[0].l, cnt);
    add(q[0].l, 1, cnt++);
    add(1, q[0].r, cnt);
    add(q[0].r, 1, cnt++);
    add(q[0].r, q[0].l, cnt);
    add(q[0].l, q[0].r, cnt++);
    //add(q[0].r, q[0].l, cnt++);


    for(int i=0; i>n>>m){
        init();
        solve();
        for(int i=0; i


你可能感兴趣的:(数据结构,莫队算法)