题目大意
给一个仙人掌,每个结点有一个权值,查询每个仙人掌的子树(算本身)(子树结点满足:必须经过该点才能到达跟,即该点是子树的割点)有多少种小于y的权值个数为奇数(或偶数)。y是每次询问时候给。
可离线,1e5个点和询问
算法分析
如果在树上那就需要用DFS序,仙人掌也有DFS序,叫做仙人掌序列嘛。
实际上就是需要先预处理出一个结点在环上的相邻结点(有一个一定是DFS的父亲结点),最后走环上的那个结点并且不算当前结点的子树。
查询就变成了区间查询,用3809的那种莫队+分块。
注意
1、我这个SB每次块都忘了初始化,所以一定要测试极限数据啊。
2、注意考虑0结点,数据中y和w都有=0的情况。
3、为了在第二次DFS的时候用vis数组记录即可,当做图的便利,否则判断挺麻烦的。
/*
维护部分:
一个支持初始化,修改,奇偶查询的分块
一段莫队算法
根据仙人掌序列得到需要被维护的序列
根据询问进行转换
仙人掌部分:
第一次DFS得到fa和son
第二次DFS得到仙人掌序列
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+105,maxm=15e4+105,maxs=1e6+105;
int tl[maxn],tr[maxn],a[maxn];
namespace Captain_Mo
{
static const int Tim=500,n=1e6;
int N,Q,ans[maxn],belong[maxs];
struct data{
int l,r,b,op,id;
friend bool operator<(data a,data b)
{
return belong[a.l]!=belong[b.l]?belong[a.l]<belong[b.l]:a.r<b.r;
}
}q[maxn];
struct block
{
int num,L[maxs/Tim+5],R[maxs/Tim+5],vis[maxs],ji[maxs/Tim+5],ou[maxs/Tim+5];
void Build()
{
L[0]=R[