[bzoj2589]Spoj 10707 Count on a tree II

来自FallDream的博客,未经允许,请勿转载,谢谢。


定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

n<=40000  m<=100000

 

写了强制在线的树上莫队...

把树分成$n^{\frac{1}{3}}$块,每个块定一个点作为中心,预处理两两中心之间的答案。然后每次询问找到那两个点的中心,像莫队那样暴力移动。显然每次最多移动$n^{\frac{2}{3}}$次,所以复杂度$m*n^{\frac{2}{3}}$   

这道题有2s,然而交上去T了 bzoj神级评测机  本机测根本T不了啊

随便搜搜题解,搜到了PoPoQQQ大爷的博文,发现大爷也T了....瞬间感觉自己写的没救了,绝望

卡常数狗我也*** 总有一天我也会用莫队卡过这道题的

然后去搜了一个靠谱做法

先分成大小为根号n的块,然后用可持久化块状数组存下每个点到根的路径上所有权值出现的最大深度,预处理好每个块顶到所有点的答案。

然后每个询问,块内的暴力查,如果在不同块,选择块顶的深度较大的点,找到它到另一个点的答案。

这样以后只要处理这个点到块顶的那条链就行了,由于我们已经预处理了每种权值的最大深度,所以我们可以判断每种权值是否已经出现了。

复杂度$O(n^{\frac{3}{2}})$

血的教训,倍增一定要把小的写前面,我tm也就T了一个号吧。

------

莫队

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector> 
#define R register
#define MN 40000
#define MK 38
#define MD 15
#define getchar() ((S==T&&(T=((S=B)+fread(B,1,1<<15,stdin)),S==T))?0:(*S++))
char B[1<<15],*S=B,*T=B;
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int head[MN+5],cnt=0,n,m,f[MK+2][MK+2][MN+1],l[MN+5],size,fa[MN+5][MD+2],dep[MN+5];
int num=0,tot=1,bel[MN+5],a[MN+5],kind[MK+1][MK+1],last=0,cap[MK+2];
bool b[MK+2][MK+2][MN+1];
vector<int> v[MN+1];
struct edge{int to,next;}e[MN*2+5];

inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
}

void dfs(int x,int f)
{
    fa[x][0]=f;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f)
        {
            int y=e[i].to;
            dep[y]=dep[x]+1;dfs(y,x);
            for(int j=0;j<v[y].size();j++)
                v[x].push_back(v[y][j]);
            if(v[x].size()>=size)
            {
                ++num;cap[num]=x;
                for(int j=v[x].size()-1;j>=0;--j)
                    bel[v[x][j]]=num;
                for(;v[x].size();) v[x].pop_back();
            }
        }
    v[x].push_back(x);
}

inline void update(int i,int j,int x)
{
    if(!b[i][j][x])
    {
        b[i][j][x]=1;
        if(++f[i][j][a[x]]==1) ++kind[i][j];
    }
    else
    {
        b[i][j][x]=0;
        if(!--f[i][j][a[x]]) --kind[i][j];
    }
}

void update_chain(int i,int j,int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    while(dep[x]>dep[y]) 
    {
        update(i,j,x);
        x=fa[x][0];
    }
    while(x!=y)
    {
        update(i,j,x);update(i,j,y);
        x=fa[x][0];y=fa[y][0];
    }
}

int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],j=0;k;k>>=1,j++)
        if(k&1) x=fa[x][j];
    if(x==y) return x;
    for(int i=MD;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main()
{
//    freopen("sb.in","r",stdin);
//    freopen("sb2.out","w",stdout);
    n=read();m=read();size=max(1,(n+MK-1)/MK);
    for(R int i=1;i<=n;i++) a[i]=l[i]=read();
    sort(l+1,l+n+1);
    for(R int i=2;i<=n;i++) if(l[i]!=l[i-1]) l[++tot]=l[i];
    for(R int i=1;i<=n;i++) a[i]=lower_bound(l+1,l+tot+1,a[i])-l;
    for(R int i=1;i<n;i++) ins(read(),read());
    dfs(1,0);
    if(v[1].size()) 
    {
        cap[++num]=1;
        for(R int i=0;i<v[1].size();i++) bel[v[1][i]]=num;
    }
    for(R int i=1;i<=MD;i++)
        for(R int j=1;j<=n;j++)
            fa[j][i]=fa[fa[j][i-1]][i-1];
    for(R int i=1;i<=num;i++)
        for(R int j=i;j<=num;j++)
        {
            int x=cap[i],y=cap[j];
            update_chain(i,j,x,y);
        }
    for(R int i=1;i<=m;i++)
    {
        int x=read(),y=read(),a=cap[bel[x]],b=cap[bel[y]],z=lca(x,y),c=min(bel[x],bel[y]),d=max(bel[x],bel[y]);
        update_chain(c,d,a,x);
        update_chain(c,d,b,y);
        update(c,d,z);
        printf("%d\n",last=kind[c][d]);
        update_chain(c,d,a,x);
        update_chain(c,d,b,y);
        update(c,d,z);
    }
    return 0;
}

靠谱做法

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MN 40000
#define MK 200
#define MD 15
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
int n,m,ans[MK+2][MN+2],a[MN+5],l[MN+5],head[MN+5],cnt=0,size,p[MN+5][MK+1],kind=0,P[MN+5],B[MN+5];
int arrnum=0,fa[MD+2][MN+2],dep[MN+5],bel[MN+5],num=0,rt[MK+5],f[MN+5],last=0,q[MN+5],top;
struct edge{int to,next;}e[MN*2+5];
struct Array
{
    int num[MK+1];
    int operator[](int x){return p[num[B[x]]][P[x]];}
    void insert(const Array&pre,int x,int dep)
    {
        int block=B[x],t=P[x];
        memcpy(num,pre.num,sizeof(num));
        memcpy(p[++arrnum],p[num[block]],sizeof(p[0]));
        p[arrnum][t]=dep;num[block]=arrnum;
    }
}s[MN+5];

inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
} 

int init(int x,int f)
{
    fa[0][x]=f;s[x].insert(s[f],a[x],dep[x]);
    q[++top]=x;int mxdp=dep[x],beg=top;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f)
        {
            int y=e[i].to;dep[y]=dep[x]+1;
            mxdp=max(mxdp,init(y,x));
        }
    if(mxdp-dep[x]>=size||beg==1) 
    {
        rt[++num]=x;
        for(int i=beg;i<=top;i++) bel[q[i]]=num;
        top=beg-1;return dep[x]-1;
    }
    else return mxdp;
}

void getans(int x,int fat,int from)
{
    if(++f[a[x]]==1) ++kind;ans[from][x]=kind;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=fat) getans(e[i].to,x,from);
    if(!--f[a[x]]) --kind;
}

int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],j=0;k;k>>=1,j++)
        if(k&1) x=fa[j][x];
    if(x==y) return x;
    for(int i=MD;i>=0;i--)
        if(fa[i][x]!=fa[i][y])
            x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}

int solve_force(int x,int y)
{
    for(top=kind=0;x!=y;x=fa[0][x])
    {
        if(dep[x]<dep[y]) swap(x,y);
        if(!f[a[x]]++) ++kind,q[++top]=a[x];    
    }
    int ans=kind+(!f[a[x]]);
    for(;top;--top) f[q[top]]=0;
    return ans;    
}

int solve_block(int x,int y)
{
    if(dep[rt[bel[x]]]<dep[rt[bel[y]]]) swap(x,y);
    int sum=ans[bel[x]][y];
    int z=rt[bel[x]],d=dep[lca(x,y)];
    for(;x!=z;x=fa[0][x])
    {
        if(!f[a[x]]&&s[z][a[x]]<d&&s[y][a[x]]<d)
            f[q[++top]=a[x]]=1,++sum;
    }
    for(;top;--top) f[q[top]]=0;
    return sum;
}

int main()
{
    n=read();m=read();size=sqrt(n);
    for(int i=1;i<=n;i++) B[i]=(i-1)/size+1,P[i]=i%size;
    for(int i=1;i<=n;i++) l[i]=a[i]=read();
    sort(l+1,l+n+1);int tot=1;
    for(int i=2;i<=n;i++) if(l[i]!=l[i-1])l[++tot]=l[i];
    for(int i=1;i<=n;i++) a[i]=lower_bound(l+1,l+tot+1,a[i])-l;
    for(int i=1;i<n;i++) ins(read(),read());
    dep[1]=1;init(1,0);
    for(int i=1;i<=num;i++) getans(rt[i],0,i);
    for(int j=1;j<=MD;j++)
        for(int i=1;i<=n;i++)
            fa[j][i]=fa[j-1][fa[j-1][i]];
    for(int i=1;i<=m;i++)
    {
        int x=read()^last,y=read();
        if(bel[x]==bel[y]) printf("%d\n",last=solve_force(x,y));
        else printf("%d\n",last=solve_block(x,y));
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/FallDream/p/bzoj2589.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值