[HDU5709]Claris Loves Painting

description

vjudge
给定一棵\(n\)点的树,每个节点上有一个颜色,每次询问一个点的子树中与这个点距离不超过\(d\)的点的颜色有多少种。强制在线。
——本题面描述转载租酥雨的博客,版权所有,仿冒必究

data range

\[\sum n,\sum m\le 5\times 10^5\]

solution

考虑线段树合并。
首先想到维护深度的线段树,处理出每个节点对应深度最前的颜色有多少个。
合并时可能会算重,如果直接维护不知道颜色的重复情况,
所以还要维护一棵颜色的线段树,记录每个颜色的最浅深度
因为这里的每一棵线段树都要用于查询,因此合并时不能向主席树那样直接指儿子,而要新建节点

复杂度\(O(nlogn)\)

Code

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FL "a"
#define fi first
#define se second
#define RG register
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-6;
const int mod=1e4;
const int N=4e5+10;
const int M=4e5+10;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INFL=1e18+1;
const ll P=100000;
inline ll read(){
  RG ll data=0,w=1;RG char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  if(ch=='-')w=-1,ch=getchar();
  while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
  return data*w;
}
inline void file(){
  srand(time(NULL)+rand());
  freopen(FL".in","r",stdin);
  freopen(FL".out","w",stdout);
}

int n,m,c[N],ans;
int head[N],nxt[N<<1],to[N<<1],cnt;
inline void add(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}

int drt[N],ds[2][20*N],sz[20*N],dtot;
#define mid ((l+r)>>1)
void dinsert(int &i,int l,int r,int p,int v){//sum of colors
  int x=++dtot;ds[0][x]=ds[0][i];ds[1][x]=ds[1][i];sz[x]=sz[i]+v;i=x;
  if(l==r)return;
  p<=mid?dinsert(ds[0][i],l,mid,p,v):dinsert(ds[1][i],mid+1,r,p,v);
}
int query(int i,int l,int r,int x,int y){
  if(!i||x>y)return 0;if(x<=l&&r<=y)return sz[i];int v=0;
  if(x<=mid)v=query(ds[0][i],l,mid,x,y);
  if(mid<y)v+=query(ds[1][i],mid+1,r,x,y);
  return v;
}
int dmerge(int a,int b){
  if(!a||!b)return a|b;int c=++dtot;
  ds[0][c]=dmerge(ds[0][a],ds[0][b]);
  ds[1][c]=dmerge(ds[1][a],ds[1][b]);
  sz[c]=sz[a]+sz[b];return c;
}

int crt[N],cs[2][20*N],mn[20*N],ctot;
void cinsert(int &i,int l,int r,int p,int v){//mindep of color
  if(!i){i=++ctot;mn[i]=inf;cs[0][i]=cs[1][i]=0;}
  mn[i]=min(mn[i],v);if(l==r)return;
  p<=mid?cinsert(cs[0][i],l,mid,p,v):cinsert(cs[1][i],mid+1,r,p,v);
}
int cmerge(int a,int b,int l,int r,int u){
  if(!a||!b)return a|b;int c=++ctot;
  if(l==r){
    dinsert(drt[u],1,n,max(mn[a],mn[b]),-1);
    mn[c]=min(mn[a],mn[b]);cs[0][c]=cs[1][c]=0;
  }
  else{
    cs[0][c]=cmerge(cs[0][a],cs[0][b],l,mid,u);
    cs[1][c]=cmerge(cs[1][a],cs[1][b],mid+1,r,u);
    mn[c]=min(mn[cs[0][c]],mn[cs[1][c]]);
  }
  return c;
}

int dep[N];
void dfs(int u){
  for(RG int i=head[u];i;i=nxt[i]){
    RG int v=to[i];dfs(v);
    crt[u]=cmerge(crt[u],crt[v],1,n,u);
    drt[u]=dmerge(drt[u],drt[v]);
  }
}

int main()
{
  int T=read();
  while(T--){
    n=read();m=read();
    ans=ctot=dtot=cnt=0;dep[1]=1;mn[0]=inf;
    for(RG int i=1;i<=n;i++)head[i]=crt[i]=drt[i]=0,c[i]=read();
    for(RG int i=2,fa;i<=n;i++)fa=read(),add(fa,i),dep[i]=dep[fa]+1;
    for(RG int i=1;i<=n;i++){
      dinsert(drt[i],1,n,dep[i],1);
      cinsert(crt[i],1,n,c[i],dep[i]);
    }
    dfs(1);
    for(RG int i=1,u,d;i<=m;i++){
      u=read()^ans;d=dep[u]+(read()^ans);
      ans=query(drt[u],1,n,1,min(d,n));printf("%d\n",ans);
    }
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjfdf/p/9919326.html