一棵树的特点就是当节点是2^x时,它就有两个儿子,否则就只有一个儿子
输入n,表示树有n层,即深度是n,接下来是m次询问(一开始是一棵空树)
每次输入有两种操作
1、1 t l r x => 第t层的第l个节点到第r个节点之间的值是x
2、2 t v => 求第t层第v个数的子树中包含的不同的值的个数
先预处理出每个节点后面的左二子和右儿子,用数组l[ ],, r[ ]记录
节点是2^x时,右儿子 = 左儿子 + 1,否则, 右儿子 = 左儿子
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
#define inf 7100
#define maxn 10001000
vector<int>l[inf], r[inf], x[inf];
int s[inf], fl[maxn], fr[maxn];
bool is_pow2(int x)
{
while(x)
{
if(x == 1) break;
if(x%2 == 1) return false;
x/=2;
}
return true;
}
void init()
{
int lp = 1;
for(int i = 1; i < maxn; i++)
{
fl[i] = lp;
if(is_pow2(i)) lp++;
fr[i] = lp++;
}
}
int main()
{
init();//预处理
int n, m, id, t, li, ri, xi, v, tot;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
scanf("%d", &id);
if(id == 1)
{
scanf("%d%d%d%d", &t, &li, &ri, &xi);
l[t].push_back(li);
r[t].push_back(ri);
x[t].push_back(xi);
}
else
{
scanf("%d%d", &t, &v);
li = ri = v, tot = 0;//li,ri是子树的左右边界
for(int i = t; i <= n; i++)
{
for(int j = 0; j < l[i].size(); j++)
{
int t1 = l[i][j], t2 = r[i][j];
if(l[i][j]<=ri && li<=r[i][j]) s[tot++] = x[i][j];
}
li = fl[li];
ri = fr[ri];
}
if(tot == 0) printf("0\n");
else
{
int ms = 1;
sort(s, s+tot);
for(int i = 1; i < tot; i++)
{
if(s[i-1] < s[i]) ms++;
}
printf("%d\n", ms);
}
}
}
return 0;
}