P6177 Count on a tree II/【模板】树分块

写了一整天,怎么调也是T,不知道题解是怎么过去的。
具体的题解感觉跟我写的也差不多我就是T,可能有点卡常,还是我哪里姿势不对。
(难道是T在了链式前向星图上???)

下面代码是T了的,主要学习一下树分块的思想吧。
树分块主要就是在树上找一下关键点。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
//#define lc (cnt<<1)
//#define rc (cnt<<1|1)
using namespace std;


char buffer[100001],*S,*T;
inline char Get_Char()
{
    if (S==T)
    {
        T=(S=buffer)+fread(buffer,1,100001,stdin);
        if (S==T) return EOF;
    }
    return *S++;
}
inline int read()
{
    char c;int re=0;
    for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
    while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
    return re;
}




const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=1e9+7;
const int maxn=40002;
const int s=1000;

int head[maxn],ver[maxn<<1],nt[maxn<<1];
int d[maxn],f[maxn],son[maxn],si[maxn];
int id[maxn],top[maxn];
int tot=1,cnt=0,tp=0,cnts=0;
int val[maxn],a[maxn],st[maxn],sid[maxn],maxd[maxn],sf[maxn];

bitset<maxn>b[maxn/s+2][maxn/s+2],nowb;

void add(int x,int y)
{
    ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}

void dfs1(int x,int fa)
{
    int max_son=0;
    si[x]=1;
    maxd[x]=d[x];
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa) continue;
        d[y]=d[x]+1;
        f[y]=x;
        dfs1(y,x);
        si[x]+=si[y];
        maxd[x]=max(maxd[x],maxd[y]);
        if(si[y]>max_son) max_son=si[y],son[x]=y;
    }
    if(maxd[x]-d[x]>=s) sid[x]=++cnts,maxd[x]=d[x];
}

void dfs1p5(int x,int fa)
{
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa) continue;
        if(sid[y])
        {
            int l=sid[st[tp]],r=sid[y];
            for(int now=y;now!=st[tp];now=f[now])
                b[l][r].set(val[now]);
            nowb=b[l][r];
            for(int j=1;j<tp;j)
                b[sid[st[j]]][r]=b[sid[st[j]]][l]|nowb;
            sf[y]=st[tp];
            st[++tp]=y;
        }
        dfs1p5(y,x);
        if(sid[y]) tp--;
    }
}

void dfs2(int x,int t)
{
    top[x]=t;
    id[x]=++cnt;
    if(!son[x]) return ;
    dfs2(son[x],t);
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y!=son[x]&&y!=f[x])
            dfs2(y,y);
    }
}

int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(d[top[x]]<d[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    return id[x]>id[y]?y:x;
}

int main(void)
{
    int n,m;
    int x,y;
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        val[i]=read();
        a[i]=val[i];
    }
    sort(a+1,a+n+1);
    int nc=unique(a+1,a+n+1)-(a+1);
    for(int i=1;i<=n;i++)
        val[i]=lower_bound(a+1,a+nc+1,val[i])-a;

    for(int i=1;i<n;i++)
    {
        x=read(),y=read();
        add(x,y);
        add(y,x);
    }


    d[1]=1;
    dfs1(1,0);

    if(sid[1]==0) sid[1]=++cnts;
    st[++tp]=1;
    dfs1p5(1,0);
    dfs2(1,1);

    int ans=0;
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read();
        x^=ans;
        nowb.reset();
        int lc=lca(x,y);
        while(x!=lc&&!sid[x]) nowb.set(val[x]),x=f[x];
        while(y!=lc&&!sid[y]) nowb.set(val[y]),y=f[y];
        if(x!=lc)
        {
            int pre=x;
            while(d[sf[pre]]>=d[lc]) pre=sf[pre];
            if(pre!=x) nowb|=b[sid[pre]][sid[x]];
            while(pre!=lc) nowb.set(val[pre]),pre=f[pre];
        }
        if(y!=lc)
        {
            int pre=y;
            while(d[sf[pre]]>=d[lc]) pre=sf[pre];
            if(pre!=y) nowb|=b[sid[pre]][sid[y]];
            while(pre!=lc) nowb.set(val[pre]),pre=f[pre];
        }
        nowb.set(val[lc]);

        printf("%d\n",ans=nowb.count());
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值