BZOJ3757: 苹果树

这篇博客介绍了如何运用树上莫队算法解决BZOJ3757问题,采用无修改的分块策略,利用王室联邦的思想进行分块。虽然博主对于复杂度分析不擅长,但分享了作为SB选手的理解和解题思路。
摘要由CSDN通过智能技术生成

树上莫队
无修改的分块
分块方法用王室联邦的方法
至于复杂度分析我不会….. 毕竟SB选手

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
char c;
inline void read(int &a)
{
    a=0;do c=getchar();while(c<'0'||c>'9');
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}


int Blo[1000001];
int Cap[1000001];

struct Query
{
    int u,v,a,b,no,ans;
    inline void Bg()
    {Blo[u]>Blo[v]?swap(u,v):swap(u,v),swap(u,v);}
    inline friend bool operator <(Query a,Query b)
    {return Blo[a.u]^Blo[b.u]?Blo[a.u]<Blo[b.u]:Blo[a.v]<Blo[b.v];}
}L[1000001];
inline bool cmp(Query a,Query b)
{return a.no<b.no;}
int B;
int F[100001][20];
int size[1000001];
struct Chain
{
    int u;
    Chain *next;
    Chain(){next=NULL;}
}*Head[1000001];
inline void Add(int a,int b)
{
    Chain *tp=new Chain;
    tp->u=b;
    tp->next=Head[a];
    Head[a]=tp;
}
int dep[1000001];
int Cache[1000001],f[1000001];
int tot,con;
void DFS(int u,int fa)
{
    f[u]=fa;
    for(Chain *tp=Head[u];tp;tp=tp->next) 
       if(tp->u!=fa)
         {
            dep[tp->u]=dep[u]+1;
            DFS(tp->u,u);
            if(tot>=B)
               {
                ++con;
                while(tot)
                    Blo[Cache[tot--]]=con;
                }
         }
    Cache[++tot]=u;   
}
int root,ans;
int Cnt[1000001],color[1000001];
bool vis[1000001];
inline void NodeXor(int a)
{
    if(vis[a])
    {
        vis[a]=false;
        Cnt[color[a]]--;
        if(!Cnt[color[a]])
           ans--;
    }
    else
      {
        vis[a]=true;
        Cnt[color[a]]++;
        if(Cnt[color[a]]==1)
          ans++;
      }
}

inline void PathXor(int a,int b)
{
    while(a^b)
    {
        if(dep[a]<dep[b])swap(a,b);
        NodeXor(a);
        a=f[a];
    }
}
int LCA(int a,int b)
{
    int j;
    while(dep[a]^dep[b])
    {
        if(dep[a]<dep[b])swap(a,b);
        for(j=0;dep[F[a][j+1]]>dep[b];j++);
        a=F[a][j];
    }
    while(a^b)
    {
        for(j=0;F[a][j+1]^F[b][j+1];j++);
        a=F[a][j],b=F[b][j];
    }
    return a;
}
int main()
{
    int i,j,n,m,k;
    read(n),read(m);
    B=sqrt(n);
    root=0;
    for(i=1;i<=n;i++)
     read(color[i]);
    for(i=1;i<=n;i++)
     {
        read(j),read(k);
        if(j==0||k==0)
          root=j==0?k:j;
          else Add(j,k);Add(k,j);
     }
    DFS(root,root);

    for(j=1;j<=n;j++)
       F[j][0]=f[j];
    for(i=1;i<=19;i++)
       for(j=1;j<=n;j++)
         F[j][i]=F[F[j][i-1]][i-1];
    ++con;
    while(tot)
        Blo[Cache[tot--]]=con;  
    for(i=1;i<=m;i++)
      read(L[i].u),read(L[i].v),read(L[i].a),read(L[i].b),L[i].no=i,L[i].Bg();
    sort(L+1,L+1+m);
//  NodeXor(root);
    int lastl=root,lastr=root;
    for(i=1;i<=m;i++)
    {
        PathXor(lastl,L[i].u),PathXor(lastr,L[i].v);
        lastl=L[i].u,lastr=L[i].v;
        int F=LCA(lastl,lastr);
        NodeXor(F);
        L[i].ans=ans+((Cnt[L[i].a]&&Cnt[L[i].b]&&L[i].b!=L[i].a)?-1:0);
        NodeXor(F);
    }
    sort(L+1,L+1+m,cmp);
    for(i=1;i<=m;i++)
      printf("%d\n",L[i].ans);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值