BZOJ3351 [ioi2009]Regions

https://www.cnblogs.com/cutemush/p/12797280.html

给定一棵有根树,每次询问所有颜色为a的节点的子树中颜色为b的节点个数之和。

 思路:

考虑将询问按b的出现次数分类。

若b<=sqrt(n),我们可以在每个b节点用一个vector记录它涉及到的询问。

dfs,用桶记录从根节点到这个节点每种颜色的出现次数,就可以更新答案了。

由于总点数为O(q*sqrt(n)),时间复杂度为O(q*sqrt(n))

若b>sqrt(n),那么只有不超过sqrt(n)种这样的颜色,我们可以在每个a节点用一个vector记录它涉及到的询问。

dfs,用桶记录子树中各颜色出现次数,更新答案。时间复杂度为O(n*sqrt(n))

所以总时间复杂度为O(q*sqrt(n)+n*sqrt(n))

具体看代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if(p1==p2){
    p2=(p1=buf)+fread(buf,1,100000,stdin);
    if(p1==p2)return EOF;
  }
  return *p1++;
}
inline void Read(int& x){
  char c=nc();
  for(;c<'0'||c>'9';c=nc());
  for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define N 200010
#define R 25010
#define ll long long
struct Node
{
  int x,y;
  Node(){}
  Node(int x,int y):x(x),y(y){}
  bool operator<(Node a)const
  {
    return x<a.x||(x==a.x&&y<a.y);
  }
}b[N];
map<Node,int>M;
vector<int>g[N],B[N],A[N];
int n,r,q,f[N],a[N],S,Tmp[R],Sum[R],i,F[N];
ll Ans[N];
inline void Dfs1(int x)
{
  Tmp[a[x]]++;
  for(int i=0;i<B[a[x]].size();i++)
      Ans[B[a[x]][i]]+=Tmp[b[B[a[x]][i]].x];
  for(int i=0;i<g[x].size();i++)
      Dfs1(g[x][i]);
  Tmp[a[x]]--;
}
inline void Dfs2(int x)
{
  for(int i=0;i<A[a[x]].size();i++)
    Ans[A[a[x]][i]]-=Tmp[b[A[a[x]][i]].y];
  Tmp[a[x]]++;
  for(int i=0;i<g[x].size();i++)
      Dfs2(g[x][i]);
  for(int i=0;i<A[a[x]].size();i++)
    Ans[A[a[x]][i]]+=Tmp[b[A[a[x]][i]].y];
}
char s[30];
int Len;
inline void Print(ll x){
  if(x==0)putchar(48);
  for(Len=0;x;x/=10)s[++Len]=x%10;
  for(;Len;)putchar(s[Len--]+48);
  putchar('\n');
}
int main()
{
  Read(n);Read(r);Read(q);
  S=(int)sqrt((double)n)+1;
  Read(a[1]);
  Sum[a[1]]++;
  for(i=2;i<=n;i++)
      Read(f[i]),
      g[f[i]].push_back(i),
      Read(a[i]),
      Sum[a[i]]++;
  for(i=1;i<=q;i++)
  {
    Read(b[i].x);
	Read(b[i].y);
	F[i]=i;
    if(M.count(Node(b[i].x,b[i].y)))
	    F[i]=M[Node(b[i].x,b[i].y)];
	else
	{
      M[Node(b[i].x,b[i].y)]=i;
      if  (Sum[b[i].y]<=S)
      //若b<=sqrt(n),我们可以在每个b节点用一个vector记录它涉及到的询问。
      //dfs,用桶记录从根节点到这个节点每种颜色的出现次数,就可以更新答案了。
	       B[b[i].y].push_back(i);
	  else 
	  //若b>sqrt(n),那么只有不超过sqrt(n)种这样的颜色,
	  //我们可以在每个a节点用一个vector记录它涉及到的询问。
      //dfs,用桶记录子树中各颜色出现次数,更新答案。时间复杂度为O(n*sqrt(n))
	       A[b[i].x].push_back(i);
    }
  }
  Dfs1(1);
  Dfs2(1);
  for(i=1;i<=q;i++)
      Print(Ans[F[i]]);
  return 0;
}

  

posted @ 2020-04-28 21:12  我微笑不代表我快乐  阅读(152)  评论(0编辑  收藏  举报