HDU 4358 莫队算法+dfs序+离散化

时间:2023-03-09 05:15:21
HDU 4358 莫队算法+dfs序+离散化

Boring counting

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others)
Total Submission(s): 2808    Accepted Submission(s): 826

Problem Description
In this problem we consider a rooted tree with N vertices. The vertices are numbered from 1 to N, and vertex 1 represents the root. There are integer weights on each vectice. Your task is to answer a list of queries, for each query, please tell us among all the vertices in the subtree rooted at vertice u, how many different kinds of weights appear exactly K times?
Input
The first line of the input contains an integer T( T<= 5 ), indicating the number of test cases.
For each test case, the first line contains two integers N and K, as described above. ( 1<= N <= 105, 1 <= K <= N )
Then come N integers in the second line, they are the weights of vertice 1 to N. ( 0 <= weight <= 109 )
For next N-1 lines, each line contains two vertices u and v, which is connected in the tree.
Next line is a integer Q, representing the number of queries. (1 <= Q <= 105)
For next Q lines, each with an integer u, as the root of the subtree described above.
Output
For each test case, output "Case #X:" first, X is the test number. Then output Q lines, each with a number -- the answer to each query.

Seperate each test case with an empty line.

Sample Input
1
3 1
1 2 2
1 2
1 3
3
2
1
3
Sample Output
Case #1:
1
1
1
Author
fish@UESTC_Oblivion
Source
题意:给你一个树  每个节点都有一个权值   q个询问 问x的子树中有多少种不同的权值出现了k次
题解:第一题莫队 莫队算法 正如莫涛本人而言这种方法是处理一类无修改的离线区间询问问题的  dfs序将子树的问题转换为区间问题
之后就是莫队的处理,只是一个神奇的算法,在我看来就是一种有技巧的暴力。另外还要注意对权值的离散化。PE orzz
 /******************************
code by drizzle
blog: www.cnblogs.com/hsd-/
^ ^ ^ ^
O O
******************************/
#include<bits/stdc++.h>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define A first
#define B second
const int mod=;
const int MOD1=;
const int MOD2=;
const double EPS=0.00000001;
typedef __int64 ll;
const ll MOD=;
const int INF=;
const ll MAX=1ll<<;
const double eps=1e-;
const double inf=~0u>>;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned int uint;
typedef unsigned long long ull;
int T;
int n,k,w[],v[],vv[],x,y,q;
int in[],out[];
int pre[];
int pos[];
int re[];
int sum[];
int dfn=;
int ans;int nedge=;
struct node
{
int pre,ed;
}N[];
struct query
{
int id;
int l,r;
}M[];
void add(int st,int ed )
{
nedge++;
N[nedge].ed=ed;
N[nedge].pre=pre[st];
pre[st]=nedge;
}
void getdfs(int now,int fa)
{
in[now]=++dfn;
for(int i=pre[now];i;i=N[i].pre)
{
if(N[i].ed!=fa)
{
getdfs(N[i].ed,now);
}
}
out[now]=dfn;
}
void init()
{
nedge=;
memset(pre,,sizeof(pre));
dfn=;
ans=;
memset(sum,,sizeof(sum));
memset(N,,sizeof(N));
memset(M,,sizeof(M));
memset(re,,sizeof(re));
memset(pos,,sizeof(pos));
memset(in,,sizeof(in));
memset(out,,sizeof(out));
memset(w,,sizeof(w));
memset(v,,sizeof(v));
memset(vv,,sizeof(vv));
}
bool cmp(struct query aa,struct query bb)
{
if(pos[aa.id]<pos[bb.id])
return true;
if(pos[aa.id]==pos[bb.id])
{
if(aa.r<bb.r)
return true;
}
return false;
}
void ad(int value)
{
if(sum[value]==k)
ans--;
sum[value]++;
if(sum[value]==k)
ans++;
}
void del(int value)
{
if(sum[value]==k)
ans--;
sum[value]--;
if(sum[value]==k)
ans++;
}
int main()
{
scanf("%d",&T);
for(int i=;i<=T;i++)
{
init();
scanf("%d %d",&n,&k);
int block=sqrt(n);
for(int j=;j<=n;j++){
scanf("%d",&w[j]);
v[j]=w[j];
}
sort(w+,w++n);
for(int j=;j<=n;j++){
v[j]=lower_bound(w+,w+n+,v[j])-w-;
}
for(int j=;j<n;j++){
scanf("%d %d",&x,&y);
add(x,y);add(y,x);
}
getdfs(,);
for(int j=;j<=n;j++)
vv[in[j]]=v[j];// 将树上的权值 下放到区间当中
scanf("%d",&q);
int exm;
for(int j=;j<=q;j++){
scanf("%d",&exm);
M[j].l=in[exm];
M[j].r=out[exm];
M[j].id=j;
pos[j]=(M[j].l)/block;//分块 处理的不是特别好
}
printf("Case #%d:\n",i);
sort(M+,M++q,cmp);
int l=, r=;//初始区间
ad(vv[++r]);
for(int j=; j<=q; j++)
{
while(r<M[j].r) ad(vv[++r]);
while(r>M[j].r) del(vv[r--]);
while(l<M[j].l) del(vv[l++]);
while(l>M[j].l) ad(vv[--l]);
re[M[j].id]=ans;
}
for(int j=;j<=q;j++)
printf("%d\n",re[j]);
if(i!=T)
printf("\n");
}
return ;
}