PASSWORD5--Count
题目链接
题意简述:
给一个\(n\)节点以\(1\)为根的树,每个点有点权,每次询问给定\([l,r]\),求\(l \leftrightarrow r\)路径上出现最多点权的出现次数
标签:树上莫队,Tarjan
思路:
序列上众数出现次数使用莫队\(\rightarrow\)树上众数出现次数使用树上莫队
树上莫队模板:SP10707 COT2 - Count on a tree II
step1.读入并将点权离散化,dfs求树的欧拉序
step2.对于询问分块排序,求两节点的LCA
step3.莫队,\(cnt_i\)表示i的出现的次数,\(t_i\)表示次数为i的答案个数,Ans表示答案
详细操作见代码
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
using namespace std;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
int n, m, k, p[N], b[N];
int id, fir[N], top[N], father[N], dep[N], siz[N], son[N], x, y;
int order[M], st[M], ed[M], tot, pos[M], Block;
int used[N], cnt[N], Ans, Cnt, t[N];
int Fans[N], Fcnt[N];
int v[N], f[N];
vector<int> Q[N], Qid[N];
struct E
{
int next, to;
}e[M];
struct Query
{
int x, y, LCA, id, ans;
bool operator < (const Query &t) const
{
if(pos[x] == pos[t.x])
return y < t.y;
return pos[x] < pos[t.x];
}
}q[N];
inline char getc()
{
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)
{
int f = 1;
x = 0;
char s = getc();
while(!isdigit(s))
{
if(s == '-')
f = -1;
s = getc();
}
while(isdigit(s))
{
x = x * 10 + s - '0';
s = getc();
}
x *= f;
}
inline void add(int x, int y)
{
e[++id].to = y;
e[id].next = fir[x];
fir[x] = id;
}
inline int find(int l)
{
if(f[l] == l)
return l;
return f[l] = find(f[l]);
}
inline void Input()
{
read(n);
read(m);
read(k);
for(int i = 1; i <= n; ++i)
{
read(p[i]);
b[i] = p[i];
}
int x;
sort(b + 1, b + n + 1);
x = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; ++i)
p[i] = lower_bound(b + 1, b + x + 1, p[i]) - b - 1;
for(int i = 1; i < n; ++i)
{
read(x);
read(y);
add(x, y);
add(y, x);
}
for(int i = 1; i <= m; ++i)
{
read(q[i].x);
read(q[i].y);
q[i].id = i;
Q[q[i].x].push_back(q[i].y);
Q[q[i].y].push_back(q[i].x);
Qid[q[i].x].push_back(i);
Qid[q[i].y].push_back(i);
}
}
inline void dfs1(int x, int fa)
{
dep[x] = dep[fa] + 1;
father[x] = fa;
order[++tot] = x;
st[x] = tot;
for(int i = fir[x]; i; i = e[i].next)
{
int v = e[i].to;
if(v == fa)
continue;
dfs1(v, x);
}
order[++tot] = x;
ed[x] = tot;
}
inline void Tarjan(int x)
{
v[x] = 1;
for(int i = fir[x]; i; i = e[i].next)
{
int y = e[i].to;
if(v[y])
continue;
Tarjan(y);
f[y] = x;
}
for(int i = 0; i < Q[x].size(); ++i)
{
int y = Q[x][i], id = Qid[x][i];
if(v[y] == 2)
q[id].LCA = find(y);
}
v[x] = 2;
}
inline void DealQuery()
{
Block = sqrt(n * 2);
for(int i = 1; i <= n * 2; ++i)
pos[i] = i / Block + 1;
for(int i = 1; i <= n; ++i)
f[i] = i;
Tarjan(1);
for(int i = 1; i <= m; ++i)
{
if(st[q[i].x] > st[q[i].y])
swap(q[i].x, q[i].y);
if(q[i].LCA == q[i].x)
{
q[i].x = st[q[i].x];
q[i].y = st[q[i].y];
q[i].LCA = 0;
}
else
{
q[i].x = ed[q[i].x];
q[i].y = st[q[i].y];
}
}
sort(q + 1, q + m + 1);
}
inline void Add(int x)
{
t[cnt[x]]--;
t[++cnt[x]]++;
Cnt = max(Cnt, cnt[x]);
}
inline void Del(int x)
{
t[cnt[x]]--;
if(Cnt == cnt[x] && !t[cnt[x]])
--Cnt;
t[--cnt[x]]++;
}
inline void update(int x)
{
//used[x] ? Del(p[x]) : Add(p[x]);
if(used[x])
{
t[cnt[p[x]]]--;
if(Cnt == cnt[p[x]] && !t[cnt[p[x]]])
--Cnt;
t[--cnt[p[x]]]++;
}
else
{
t[cnt[p[x]]]--;
t[++cnt[p[x]]]++;
Cnt = max(Cnt, cnt[p[x]]);
}
used[x] ^= 1;
}
int main()
{
ios::sync_with_stdio(false);
Input();
dfs1(1, 0);
DealQuery();
int l = 1, r = 0;
for(int i = 1; i <= m; ++i)
{
while(l < q[i].x)
update(order[l++]);
while(l > q[i].x)
update(order[--l]);
while(r < q[i].y)
update(order[++r]);
while(r > q[i].y)
update(order[r--]);
if(q[i].LCA)
update(q[i].LCA);
q[i].ans = Cnt;
if(q[i].LCA)
update(q[i].LCA);
}
//cout << "ANS" << endl;
for(int i = 1; i <= m; ++i)
Fans[q[i].id] = q[i].ans;
for(int i = 1; i <= m; ++i)
{
cout << Fans[i] << ' ';
if(Fans[i] > k)
cout << "NO" << '\n';
else
cout << "YES" << '\n';
}
return 0;
}