返回顶部
扩大
缩小

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;
}
posted @ 2019-08-26 19:42  Asasino  阅读(147)  评论(0编辑  收藏  举报