zoukankan      html  css  js  c++  java
  • 树上莫队

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

    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
    ",anss[i]);
    }
  • 相关阅读:
    scrapy user-agent随机更换
    python框架Scrapy中crawlSpider的使用——爬取内容写进MySQL
    异步代理池2--正确实现并发
    python asyncio异步代理池
    SSH 上传下载文件
    scrapy 自定义扩展
    scrapy pipelines 以及 cookies
    scrapy 去重策略修改
    提车注意事项
    mysql 笔记
  • 原文地址:https://www.cnblogs.com/zzqsblog/p/5627680.html
Copyright © 2011-2022 走看看