小度是这场比赛的出题人。作为一个良心出题人,他非常不希望这场比赛有人AK。但是作为一个菜鸡,他又没有能力出难题,怎么办呢?无奈的他准备去搬原题。
他发现,很多题目都是从经典题派生而来。具体地,1号题是唯一的一道原创题,其他的每道题都恰好由一道编号小于它的题直接派生而来。他在研究这些题考察的知识点的异同。
小度进行了m次操作,每次,小度会做下列两种操作之一:
1 x y 表示对于题目x,小度发现了一个考察的知识点y。(该题原有的知识点保持不变)
2 x y 表示对于题目x,询问所有由x派生的题目中,考察知识点y的有多少。
注意:
- 派生题这个词是出题人随便编的,所以派生题不继承母题考察的知识点。
- 操作可能重复输入,遇到重复的1操作请忽略。
格式
输入格式:
输入第一行为一个整数n,表示题目的数量。
第2行为n-1个整数,分别表示第2到n号题由哪道题派生而来。
第3行为一个整数m,表示操作数量。
接下来m行,每行都形如1 x y或者2 x y,含义见上。
输出格式:
对于每一个2操作,输出其答案并且换行。
样例 1
输入:
6
1 1 2 2 3
8
1 4 1
2 2 1
1 6 1
2 1 1
1 4 2
2 2 2
1 4 2
2 2 2
输出:
1
2
1
1
我写的代码 样例1对了,但是提交一直不对
import java.util.Scanner;
import java.util.*;
class Main {
private static int[][] pages;//邻接矩阵,记录边,也就是记录题目之间的关系
private static boolean[] flag;//记录题目是否访问过
private static List<List<Integer>> vt;//存储题目所发现的知识点
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// code here
int n = input.nextInt();
init(n);
for(int i = 0; i < n; i ++) {
List<Integer> list = new ArrayList<>();
vt.add(list);
}
//题目下标都是从0开始的,j为题目,从第二题开始
for(int j = 1; j < n;j++) {
int x = input.nextInt();
insertPages(x-1,j,1);//插入边,例2是1的派生题,则插入边为0,1,1权值记为1
}
int n2 = input.nextInt();
for(int i = 0; i < n2;i++) {
int a = input.nextInt();//记录操作数
int x = input.nextInt();
int y = input.nextInt();
if(a == 1) {//操作数为1时,加入发现的知识点
List<Integer> list = vt.get(x-1);
if(ish(list,y)) {//ish方法是判断是否重复,题目为已经发现的知识点,插入1次即可
list.add(y);
}
}else{
flag = new boolean[n];//这里是每次寻找派生题时,都置为false
//index 该题的下标
//要寻找的知识点
//记录知识点
//s 该s变量时记录进入dfs的第一题,它为头节点,也就是要寻找它派生题的知识点,它自己是不需要寻找的
System.out.println(dfs(x-1,y,0,x-1));//使用dfs遍历该x题的所有派生题
}
}
input.close();
}
/**
* 判断是否重复加入知识点
* @param list
* @param y
* @return
*/
public static boolean ish(List<Integer> list,int y) {
for(Integer k:list) {
if(y == k) {
return false;
}
}
return true;
}
/**
*
* @param index 该题的下标
* @param y 要寻找的知识点
* @param count 记录知识点
* @param s 该s变量时记录进入dfs的第一题,它为头节点,也就是要寻找它派生题的知识点,它自己是不需要寻找的
* @return
*/
public static int dfs(int index,int y,int count,int s) {
flag[index] = true;
if(index != s) {//寻找该题派生题的知识点,它自己是不需要寻找的
for(Integer i:vt.get(index)) {
if(i == y) {
count ++;//发现知识点就+1
}
}
}
int w = getFirstIndex(index);//寻找该题的首个派生题,-1说明已经没有派生题了
while(w != -1) {
if(!flag[w]) {
count = dfs(w,y,count,s);
}else{
w = getNextIndex(index,w);
}
}
return count;
}
//返回该节点最近的下一个节点
public static int getFirstIndex(int v) {
for(int i = 0; i < pages.length;i++ ){
if(pages[v][i] > 0) {
return i;
}
}
return -1;
}
//寻找其他的邻接节点
public static int getNextIndex(int v1,int v2) {
for(int i = v2+1;i < pages.length; i++) {
if(pages[v1][i] > 0) {
return i;
}
}
return -1;
}
public static void init(int n) {
pages = new int[n][n];
vt = new ArrayList<>();
}
public static void insertPages(int v1, int v2, int weigth) {
pages[v1][v2] = weigth;
}
}