简介
- 可以解决区间众数问题
- 不能支持修改,只能支持子树统计,不能链上统计。
- 和并查集无关
理解
假设给定一棵树,每个节点都有自己的颜色,现多次询问要求以某结点为根的子树内数量最多的颜色的编号。暴力即是对于询问
的每一个节点递归统计颜色求最大,但是如果数据过大即使预处理各节点答案也可以导致n2复杂度。考虑每个节点的求解过程,都是要统计完子树的才更新自己,我们如果把统计子树内颜色个数的数组定为cnt,则cnt在一个子树用完后被另一个子树用时必须清空,这导致了低效。可以发现统计子树的颜色时,最后一个被统计的子树不必被清空,这在递归中自然不好特判,但我们可以利用这个性质,先求出非重子树的贡献,清空cnt,再求出重子树cnt,并利用这时的cnt再跑一遍非重子树加上其贡献。复杂度可以达到令人惊讶的O(nlogn);
Lomsat gelral
分析
已经分析了吧...
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
using namespace std;
template <typename xxx> inline void read(xxx &x) {
char c = getchar(),f = 1;x = 0;
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') c = getchar(),f = -1;
for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
x *= f;
}
template<typename xxx>void print(xxx x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int maxn = 100010;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
struct edge{
int to,last;
}e[maxn<<1];
int head[maxn],tot;
void add(int from,int to) {
++tot;
e[tot].to = to;
e[tot].last = head[from];
head[from] = tot;
}
int siz[maxn],son[maxn];
void dfs(int x,int da) {//重链剖分
siz[x] = 1;
for(rint i = head[x]; i; i = e[i].last) {
if(e[i].to == da) continue;
dfs(e[i].to,x);
siz[x] += siz[e[i].to];
if(son[x] == 0 || siz[son[x]] < siz[e[i].to]) son[x] = e[i].to;
}
return ;
}
int cnt[maxn];
ll sum,ans[maxn],Mx,Tem,col[maxn];
void deal(int x,int da,int val) {
cnt[col[x]] +=val;//因题而异
if(cnt[col[x]] > Mx) Mx = cnt[col[x]],sum = col[x];
else if(cnt[col[x]] == Mx) sum += col[x];
for(rint i = head[x]; i; i = e[i].last) {
if(e[i].to == da || e[i].to == Tem) continue;
deal(e[i].to,x,val);
}
}
void ddfs(int x,int da,int opt) {
for(rint i = head[x]; i; i = e[i].last) {
if(e[i].to == da) continue;
if(e[i].to ^ son[x]) ddfs(e[i].to,x,0);//暴力统计轻边的贡献,opt = 0表示递归完成后要消除对该点的影响
}
if(son[x]) ddfs(son[x],x,1),Tem = son[x];//统计重儿子的贡献,不消除影响
deal(x,da,1);Tem = 0;//暴力统计所有轻儿子的贡献
ans[x] = sum;//更新答案
if(!opt) deal(x,da,-1),sum = 0,Mx = 0;//如果需要删除贡献的话就删掉
return ;
}
int n;
int main()
{
read(n);
for(rint i = 1;i <= n; ++i) read(col[i]);
for(rint i = 2;i <= n; ++i) {
int x,y;
read(x);read(y);
add(x,y);add(y,x);
}
dfs(1,0);
ddfs(1,0,0);
for(rint i = 1;i <= n; ++i) print(ans[i]),putchar(' ');
return 0;
}
/*
*/
Blood Cousins
分析
和上一题差不多,转化一下就好了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
using namespace std;
template <typename xxx> inline void read(xxx &x) {
char c = getchar(),f = 1;x = 0;
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') c = getchar(),f = -1;
for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
x *= f;
}
template<typename xxx>void print(xxx x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int maxn = 200110;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
struct edge{
int to,last;
}e[maxn<<1];
int tot,head[maxn];
inline void add(int from,int to) {
++tot;
e[tot].to = to;
e[tot].last = head[from];
head[from] = tot;
}
int n,m;
struct node{int id,dth;};
vector<node>q[maxn];
int fa[22][maxn],lg[maxn];
int son[maxn],siz[maxn];
ll tem;
int ans[maxn],cnt[maxn];
int dep[maxn];
inline void dfs(int x,int da) {
dep[x] = dep[da] + 1;
fa[0][x] = da;siz[x] = 1;
for(rint i = 1;i <= lg[dep[x]]; ++i) {
fa[i][x] = fa[i - 1][fa[i - 1][x]];
}
for(rint i = head[x];i;i = e[i].last) {
if(e[i].to == da) continue;
dfs(e[i].to,x);
siz[x] += siz[e[i].to];
if(son[x] == 0 || siz[son[x]] < siz[e[i].to]) son[x] = e[i].to;
}
return;
}
inline void deal(int x,int da,int val) {
cnt[dep[x]] += val;
for(rint i = head[x];i;i = e[i].last) {
if(e[i].to == tem || e[i].to == da) continue;
deal(e[i].to,x,val);
}
return ;
}
inline void ddfs(int x,int da,int opt) {
for(rint i = head[x];i;i = e[i].last) {
if(e[i].to == da || e[i].to == son[x]) continue;
ddfs(e[i].to,x,0);
}
if(son[x]) ddfs(son[x],x,1),tem = son[x];
deal(x,da,1);
tem = 0;
int lim = q[x].size();
for(rint i = 0;i < lim ; ++i) ans[q[x][i].id] = cnt[q[x][i].dth] - 1;
if(!opt) deal(x,da,-1);
return;
}
inline int gt(int x,int y) {
while(y)
x=fa[lg[y]][x],
y-=(1<<lg[y]);
return x;
}
int main()
{
read(n);
for(rint i = 2;i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for(rint i = 1;i <= n; ++i) {
int x;read(x);
++x;//以1为超级节点
add(x,i + 1);
}
dep[0] = -1;
dfs(1,0);
read(m);
for(rint i = 1;i <= m; ++i) {
int x,y;
read(x);read(y);++x;
// cout<<gt(x,y)<<endl;
if(dep[x] < y + 1) continue;
q[gt(x,y)].push_back((node){i,dep[x]});
}
ddfs(1,0,0);
for(rint i = 1;i <= m; ++i) print(ans[i]),putchar(' ');
return 0;
}
/*
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
*/