3572: [Hnoi2014]世界树 虚树+DP

虚树裸题,正反DP一遍求答案。
写了一发rmqlca发现比倍增慢。。这个显然调用超过n次了啊。。为什么 O(nlogn) 预处理 O(1) 查询会比超过 n O(logn)查询慢?
bzoj傻逼样例没空格,样例在程序最下面。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 300005
using namespace std;
int n,m,Q,cnt,dfn,top,eul;
int fa[N][20];
int a[N],b[N],f[N],stack[N],point[N],rem[N],belong[N],deep[N],head[N],id[N],size[N],pos[N];
int next[N<<1],list[N<<1];
pair<int,int> ss[N<<1],st[N<<1][21];
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
void dfs(int x)
{
    id[x]=++dfn; size[x]=1; ss[++eul]=make_pair(deep[x],x); pos[x]=eul;
    for (int i=1;(1<<i)<=deep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x][0])
        {
            fa[list[i]][0]=x;
            deep[list[i]]=deep[x]+1;
            dfs(list[i]);
            size[x]+=size[list[i]];
            ss[++eul]=make_pair(deep[x],x);
        }
}
inline void make_st()
{
    for (int i=1;i<=eul;i++) st[i][0]=ss[i];
    for (int j=1;j<=20;j++)
        for (int i=1;i<=eul;i++)
            if (i+(1<<j)-1<=eul)
                st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int lca(int x,int y)
{
    int l=pos[x],r=pos[y];
    if (l>r) swap(l,r);
    int k=log2(r-l+1);
    pair<int,int> ans=min(st[l][k],st[r-(1<<k)+1][k]);
    return ans.second;
}
inline bool cmp(int a,int b)
{
    return id[a]<id[b];
}
inline int dis(int x,int y)
{
    return deep[x]+deep[y]-(deep[lca(x,y)]<<1);
}
void dp1(int x)
{
    point[++dfn]=x; rem[x]=size[x]; 
    for (int i=head[x];i;i=next[i])
    {
        dp1(list[i]);
        if (!belong[list[i]]) continue;
        int t1=dis(belong[list[i]],x),t2=dis(belong[x],x);
        if (t1<t2||!belong[x]||(t1==t2&&belong[list[i]]<belong[x]))
            belong[x]=belong[list[i]];
    }
}
void dp2(int x)
{
    for (int i=head[x];i;i=next[i])
    {
        int t1=dis(belong[x],list[i]),t2=dis(belong[list[i]],list[i]);
        if (t1<t2||!belong[list[i]]||(t1==t2&&belong[x]<belong[list[i]]))
            belong[list[i]]=belong[x];
        dp2(list[i]);
    }
}
void solve(int a,int b)
{
    int x=b,mid=b;
    for (int i=18;~i;i--)
        if (deep[fa[x][i]]>deep[a]) 
            x=fa[x][i];
    rem[a]-=size[x];
    if (belong[a]==belong[b])
    {
        f[belong[a]]+=size[x]-size[b];
        return;
    }
    for (int i=18;~i;i--)
    {
        if (deep[fa[mid][i]]<=deep[a]) continue;
        int t=fa[mid][i];
        int t1=dis(belong[a],t),t2=dis(t,belong[b]);
        if (t1>t2||(t1==t2&&belong[a]>belong[b])) mid=t;
    }
    f[belong[a]]+=size[x]-size[mid];
    f[belong[b]]+=size[mid]-size[b];
}
inline void query()
{
    m=read();
    for (int i=1;i<=m;i++) a[i]=b[i]=read();
    for (int i=1;i<=m;i++) belong[a[i]]=a[i];
    sort(a+1,a+m+1,cmp);
    top=0; dfn=0; cnt=0;
    if (belong[1]!=1) stack[++top]=1;
    for (int i=1;i<=m;i++)
    {
        int t=a[i],f;
        while (top)
        {
            f=lca(stack[top],t);
            if (top>1&&deep[f]<deep[stack[top-1]]) 
                insert(stack[top-1],stack[top]),top--;
            else if (deep[f]<deep[stack[top]]) 
            {
                insert(f,stack[top]);
                top--;
                break;
            }
            else break;
        }
        if (stack[top]!=f) stack[++top]=f; stack[++top]=t;
    }
    while (top>1) insert(stack[top-1],stack[top]),top--;
    dp1(1); dp2(1);
    for (int i=1;i<=dfn;i++)
        for (int j=head[point[i]];j;j=next[j])
            solve(point[i],list[j]);
    for (int i=1;i<=dfn;i++) 
        f[belong[point[i]]]+=rem[point[i]];
    for (int i=1;i<=m;i++) 
        printf("%d ",f[b[i]]); 
    puts("");
    for (int i=1;i<=dfn;i++)
        head[point[i]]=rem[point[i]]=belong[point[i]]=f[point[i]]=0;
}
int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read();
        insert(u,v); insert(v,u);
    }
    dfs(1);
    make_st();
    memset(head,0,sizeof(head)); 
    Q=read();
    while (Q--) query();
    return 0;
}
/*
10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8

1 9 
3 1 4 1 1 
10 
1 1 3 5 
4 1 3 1 1 
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值