4.1-4.5算法刷题笔记(17道题)

4.1-4.5算法刷题笔记

    • 1. 区间和
    • 2. 区间合并
    • 3. 用队列实现栈(queueMain = queueTemp;)
    • 4. 最小栈
  • 1. 单链表模板
    • 5. 单链表
  • 2. 双链表模板
    • 6. 双链表
  • 3. 模拟栈
    • 7. 模拟栈(一个数组即可)
    • 8. 表达式求值
  • 4. 队列 tt = -1,hh = 0;
    • 9. 模拟队列
  • 5. 单调栈
    • 10. 单调栈
  • 6. 单调队列
    • 11. 滑动窗口最大值
  • 7. KMP
    • 12. KMP字符串
  • 8. Trie树
    • 13. Trie字符串统计
    • 14. 最大异或对
  • 9. 并查集 find merge
    • 15. 合并集合
    • 16. 连通块中点的数量(每个集合有多少个元素)
    • 17. 食物链

1. 区间和

原题链接

在这里插入图片描述

import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();pair[] add = new pair[n+2];pair[] query = new pair[m];List<Integer> arrayMap = new ArrayList<>(n+m*2);int[] sum = new int[n+m*2];for (int i = 0; i < n; i++) {add[i] = new pair();add[i].l = scanner.nextInt();add[i].r = scanner.nextInt();arrayMap.add(add[i].l);}for (int i = 0; i < m; i++) {query[i] = new pair();query[i].l = scanner.nextInt();query[i].r = scanner.nextInt();arrayMap.add(query[i].l);arrayMap.add(query[i].r);}arrayMap = new ArrayList<>(new HashSet<>(arrayMap));Collections.sort(arrayMap);for (int i = 0; i < n; i++) {sum[arrayMapIndexOf(add[i].l,arrayMap)] += add[i].r;}for (int i = 0; i < arrayMap.size(); i++) {if(i != 0) {sum[i] += sum[i-1];}}for (int i = 0; i < query.length; i++) {int l = arrayMapIndexOf(query[i].l,arrayMap);int r = arrayMapIndexOf(query[i].r,arrayMap);if (l == 0) {System.out.print(sum[r] + "\n");} else {System.out.print(sum[r]-sum[l-1] + "\n");}}}static class pair {int l;int r;}private static int arrayMapIndexOf(int k,List<Integer> arrayMap) {int l = 0,r = arrayMap.size()-1;while (l < r) {int mid = (l+r+1) >> 1;if (arrayMap.get(mid) <= k) {l = mid;} else {r = mid - 1;}}return r;}
}

2. 区间合并

原题链接

import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();pair[] range = new pair[n];for (int i = 0; i < n; i++) {range[i] = new pair();range[i].l = scanner.nextInt();range[i].r = scanner.nextInt();}Arrays.sort(range,new Comparator<pair>(){@Overridepublic int compare(pair o1,pair o2) {if (o1.l == o2.l) {return o1.r - o2.r;} else {return o1.l - o2.l;}}});int st = (int)-2e9-1;int ed = (int)-2e9-1;int cnt = 0;for (int i = 0; i < n; i++) {if (ed < range[i].l) {st = range[i].l;ed = range[i].r;cnt++;} else {ed = Math.max(ed,range[i].r);}}System.out.print(cnt);}static class pair {int l;int r;}}

3. 用队列实现栈(queueMain = queueTemp;)

原题链接

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;class MyStack {public Queue<Integer> queueMain;public Queue<Integer> queueTemp;public MyStack() {queueMain = new LinkedList<>();queueTemp = new LinkedList<>();}public void push(int x) {queueMain.add(x);}public int pop() {int x = 0;while (!queueMain.isEmpty()) {x = queueMain.poll();if (!queueMain.isEmpty()) {queueTemp.add(x);}}queueMain = queueTemp;queueTemp = new LinkedList<>();return x;}public int top() {int x = 0;while (!queueMain.isEmpty()) {x = queueMain.poll();queueTemp.add(x);}queueMain = queueTemp;queueTemp = new LinkedList<>();return x;}public boolean empty() {return queueMain.isEmpty();}
}/*** Your MyStack object will be instantiated and called as such:* MyStack obj = new MyStack();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.top();* boolean param_4 = obj.empty();*/

4. 最小栈

原题链接

class MinStack {Stack<Integer> A, B;public MinStack() {A = new Stack<>();B = new Stack<>();}public void push(int x) {A.add(x);if(B.empty() || B.peek() >= x)B.add(x);}public void pop() {if(A.pop().equals(B.peek()))B.pop();}public int top() {return A.peek();}public int getMin() {return B.peek();}
}

1. 单链表模板

5. 单链表

acwing链接
力扣

class MyLinkedList {int size;ListNode head;public MyLinkedList() {size = 0;head = new ListNode(0);}public int get(int index) {if (index < 0 || index >= size) {return -1;}ListNode cur = head;for (int i = 0; i <= index; i++) {cur = cur.next;}return cur.val;}public void addAtHead(int val) {addAtIndex(0, val);}public void addAtTail(int val) {addAtIndex(size, val);}public void addAtIndex(int index, int val) {if (index > size) {return;}index = Math.max(0, index);size++;ListNode pred = head;for (int i = 0; i < index; i++) {pred = pred.next;}ListNode toAdd = new ListNode(val);toAdd.next = pred.next;pred.next = toAdd;}public void deleteAtIndex(int index) {if (index < 0 || index >= size) {return;}size--;ListNode pred = head;for (int i = 0; i < index; i++) {pred = pred.next;}pred.next = pred.next.next;}
}class ListNode {int val;ListNode next;public ListNode(int val) {this.val = val;}
}
import java.util.*;public class Main {static int[] e = new int[100010];static int[] ne = new int[100010];static int idx,head;public static void init() {idx = 0;head = -1;}public static void add_head(int x) {e[idx] = x;ne[idx] = head;head = idx++;} public static void add(int k,int x) {e[idx] = x;ne[idx] = ne[k];ne[k] = idx++;}public static void remove(int k) {ne[k] = ne[ne[k]];}public static void main(String[] args) {Scanner scan = new Scanner(System.in);int m = scan.nextInt();init();while(m -- > 0){String s = scan.next();char op = s.charAt(0);if(op == 'H'){int x = scan.nextInt();add_head(x);}else if(op == 'D'){int k = scan.nextInt();if(k == 0) head = ne[head];else remove(k-1);}else {int k = scan.nextInt();int x = scan.nextInt();add(k-1,x);}}for(int i = head;i != -1;i = ne[i] ){System.out.print(e[i] +  " ");}}
}

2. 双链表模板

void init()
{r[0] = 1;l[1] = 0;idx = 2;
}

6. 双链表

原题链接
在这里插入图片描述

import java.util.Scanner;
public class Main{static int N = 100010;static int[] e = new int[N];static int[] r = new int[N];static int[] l = new int[N];static int idx;//删除第k位插入的数public static void remove(int k){r[l[k]] = r[k];l[r[k]] = l[k];}//这是在第k位数后面插入一个数xpublic static void add_all(int k,int x){e[idx] = x;r[idx] = r[k];l[idx] = k;l[r[k]] = idx;r[k] = idx++;}public static void main(String[] args){Scanner scan = new Scanner(System.in);int m = scan.nextInt();r[0] = 1;l[1] = 0;idx = 2;while(m -- > 0){String s = scan.next();char op = s.charAt(0);if(op == 'L'){int x = scan.nextInt();add_all(0,x);}else if(op == 'R'){int x = scan.nextInt();add_all(l[1],x);}else if(op == 'D'){int k = scan.nextInt();remove(k + 1);}else if(s.equals("IR")){int k  = scan.nextInt();int x = scan.nextInt();add_all(k + 1,x);}else {int k = scan.nextInt();int x = scan.nextInt();add_all(l[k+1],x);}}for(int i = r[0];i != 1; i= r[i]){System.out.print(e[i]  + " ");}}
}

3. 模拟栈

7. 模拟栈(一个数组即可)

原题链接
在这里插入图片描述

import java.util.Scanner;
public class Main{public static void main(String[] args){Scanner scan = new Scanner(System.in);int m = scan.nextInt();int[] stl = new int[100010];int tt = 0;while(m -- > 0){String s = scan.next();if(s.equals("push")){int x= scan.nextInt();stl[++tt] = x;}else if(s.equals("pop")){tt--;}else if(s.equals("empty")){if(tt > 0){System.out.println("NO");}else System.out.println("YES");}else{System.out.println(stl[tt]);}}}
} 

8. 表达式求值

原题链接

import java.util.*;
public class Main{public static void main(String[] args){Scanner scan = new Scanner(System.in);//以字符串形式输入表达式String s = scan.next();//map来添加运算符号进去,定义优先级Map<Character,Integer> map = new HashMap<>();map.put('+',1);map.put('-',1);map.put('*',2);map.put('/',2);Stack<Character> op = new Stack<>();//存运算符号Stack<Integer> num = new Stack<>();//存数字for(int i = 0 ; i < s.length(); i ++ ){char c = s.charAt(i);//判断c字符是不是数字if(Character.isDigit(c)){int x = 0,j = i;//数字可能会是多位数,while(j < s.length() && Character.isDigit(s.charAt(j))){x = x * 10 + s.charAt(j) - '0';j++;}num.push(x);//将数字x存入数字栈栈顶i = j - 1;//重新赋值i}else if(c == '('){op.push(c); // 将左括号存入字符栈栈顶}else if(c == ')'){//如果栈顶不等于左括号,一直计算下去;while(op.peek() != '('){eval(op,num);}op.pop(); // 将左括号弹出栈顶}else { //如果是正常字符while(!op.empty() && op.peek() != '(' && map.get(op.peek()) >= map.get(c)){eval(op,num);}op.push(c);}}while(!op.empty()) eval(op,num);System.out.println(num.peek());}public static void eval(Stack<Character> op,Stack<Integer> num){int b = num.pop();int a = num.pop();char c = op.pop();if(c == '+'){num.push(a+b);}else if(c == '-'){num.push(a-b);}else if(c == '*'){num.push(a*b);}else {num.push(a/b);}}
}

4. 队列 tt = -1,hh = 0;

9. 模拟队列

原题链接

import java.util.Scanner;
public class Main{public static void main(String[] args){Scanner scan = new Scanner(System.in);int m = scan.nextInt();//队列是在tt队尾插入元素,队头hh弹出元素int[] dl = new int[100010];int hh = 0;int tt = -1;while(m -- > 0){String s = scan.next();if(s.equals("push")){int x = scan.nextInt();dl[++tt] =  x;}else if(s.equals("pop")){hh++;}else if(s.equals("empty")){if(hh <= tt) System.out.println("NO");else System.out.println("YES");}else {System.out.println(dl[hh]);}}}
}

5. 单调栈

常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{while (tt && check(stk[tt], i)) tt -- ;stk[ ++ tt] = i;
}

10. 单调栈

力扣链接
原题链接

原题链接

import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int[] nums = new int[n+2];int[] st = new int[n+2];int tt = 0;for (int i = 0; i < n; i++) nums[i] = scanner.nextInt();for (int i = 0; i < n; i++) {while (tt != 0 && st[tt-1] >= nums[i]) {tt--;}if (tt == 0) {System.out.print(-1 + " ");} else {System.out.print(st[tt-1] + " ");}st[tt++] = nums[i];}}
}

6. 单调队列

11. 滑动窗口最大值

力扣链接
原题链接
原题链接

class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] q = new int[nums.length];int hh = 0, tt = -1;int[] ans = new int[nums.length-k+1];for (int i = 0; i < nums.length; i++) {int x = nums[i];if (hh <= tt && q[hh] + k <= i) {hh++;}while (hh <= tt && x >= nums[q[tt]]) {tt--;}q[++tt] = i;if (i+1 >= k) {ans[i-k+1] = nums[q[hh]];}}return ans;}
}

7. KMP

12. KMP字符串

力扣链接
acwing链接

class Solution {public int strStr(String haystack, String needle) {int[] ne = new int[haystack.length()+2];ne[0] = -1;for (int i = 1,j = -1; i < needle.length(); i++) {while (j != -1 && needle.charAt(j+1) != needle.charAt(i)) {j = ne[j];}if (needle.charAt(j+1) == needle.charAt(i)) {j++;}ne[i] = j;}int ans = 0;for (int i = 0,j = -1; i < haystack.length(); i++) {while (j != -1 && haystack.charAt(i) != needle.charAt(j+1)) {j = ne[j];}if (haystack.charAt(i) == needle.charAt(j+1)) {j++;}if (j == needle.length()-1) {return i-needle.length()+1;}}return -1;}
}

8. Trie树

13. Trie字符串统计

力扣链接
acwing链接

class Trie {public int N,idx;public int[][] song;public int[] cnt;public char[] str;public Trie() {N = 100010;idx = 0;song = new int[N][26];cnt  = new int[N];str = new char[N];}public void insert(String word) {char[] str = word.toCharArray();int p = 0; //下标0表示头结点,根节点for(int i = 0 ; i < str.length; i ++ ){// 将字符串每个字符都转化成数字;0-25int u = str[i] - 'a'; //如果这个的儿子分支没有字符,说明这条分支还没有这个字符插入过//就新建一个然后赋值为然后把【idx】下标赋值上去,作为每个分支的专属坐标if(song[p][u] == 0) song[p][u] = ++idx;//然后将p往下前进一层p = song[p][u];}//最后停在那一层的那个数字就做标记,说明这是一个字符串的结束。cnt[p]++;}public boolean search(String word) {char[] str = word.toCharArray();int p = 0;//从根节点开始,下标是0表示根节点,头结点for(int i = 0 ; i < str.length; i ++){int u = str[i] - 'a'; // 将字符串每个字符都转化成数字0-25//如果这个点上面没有标记,就说明没有存入过这个字符,所以返回0if(song[p][u] == 0) return false;//如果这个点上面能寻找到这个字符,就让他往下一层继续寻找;p = song[p][u];}//最后查找完之后输出最后一个做标记的点为下标的cnt数组的值。return cnt[p] != 0;}public boolean startsWith(String prefix) {char[] str = prefix.toCharArray();int p = 0;//从根节点开始,下标是0表示根节点,头结点for(int i = 0 ; i < str.length; i ++){int u = str[i] - 'a'; // 将字符串每个字符都转化成数字0-25//如果这个点上面没有标记,就说明没有存入过这个字符,所以返回0if(song[p][u] == 0) return false;//如果这个点上面能寻找到这个字符,就让他往下一层继续寻找;if (i == str.length-1) {return song[p][u] != 0;}p = song[p][u];}//最后查找完之后输出最后一个做标记的点为下标的cnt数组的值。return false;}
}/*** Your Trie object will be instantiated and called as such:* Trie obj = new Trie();* obj.insert(word);* boolean param_2 = obj.search(word);* boolean param_3 = obj.startsWith(prefix);*/
import java.util.Scanner;
public class Main{static int N = 100010,idx = 0;static int[][] song = new int[N][26];static int[] cnt  = new int[N];static char[] str = new char[N];public static  void insert(char[] str){int p = 0; //下标0表示头结点,根节点for(int i = 0 ; i < str.length; i ++ ){// 将字符串每个字符都转化成数字;0-25int u = str[i] - 'a'; //如果这个的儿子分支没有字符,说明这条分支还没有这个字符插入过//就新建一个然后赋值为然后把【idx】下标赋值上去,作为每个分支的专属坐标if(song[p][u] == 0) song[p][u] = ++idx;//然后将p往下前进一层p = song[p][u];}//最后停在那一层的那个数字就做标记,说明这是一个字符串的结束。cnt[p]++;}public static int query(char[] str){int p = 0;//从根节点开始,下标是0表示根节点,头结点for(int i = 0 ; i < str.length; i ++){int u = str[i] - 'a'; // 将字符串每个字符都转化成数字0-25//如果这个点上面没有标记,就说明没有存入过这个字符,所以返回0if(song[p][u] == 0) return 0;//如果这个点上面能寻找到这个字符,就让他往下一层继续寻找;p = song[p][u];}//最后查找完之后输出最后一个做标记的点为下标的cnt数组的值。return cnt[p];}public static void main(String[] args){Scanner scan = new Scanner(System.in);int n = scan.nextInt();String sss = scan.nextLine();while(n -- > 0){String s = scan.nextLine();String[] st = s.split(" ");String s1 = st[0];String s2 = st[1];if(s1.equals("I")){insert(s2.toCharArray());}else{System.out.println(query(s2.toCharArray()));}}}
}

14. 最大异或对

力扣链接
acwing链接

class Solution {public static int N,idx;public static int[][] song;public static void add(int x){int p = 0;//从头结点开始for(int i = 30 ; i >= 0 ; i -- ){ //因为每一个数的二进制是有31位组成,所以需要从大开始遍历int u = x >> i & 1;//每一个数的二进制31个二进制每一位看0还是1if(song[p][u] == 0) song[p][u] = ++idx;//判断这一层是空的,就创建,然后赋值下标p = song[p][u];//然后让往下前进一层}}//查询public static int query(int x){int p = 0,res = 0;//从根节点0开始。res进就算异或后的最大值for(int i = 30; i>= 0 ; i --){int u = x >> i & 1;if(song[p][1-u] != 0){ //如果该节点的u是0,则判断一下在这一层有没有跟他相反的0-1,1-0,如果相反对应位置有数res += (1 << i);//res就将该二进制位对应异或之后的最优解1每一位顺次加起来。因为是异或相反数就是1,这是最优解p = song[p][1-u];//然后往最优解那边前进一层。}else{//否则就不是最优解的0匹配1,1匹配0,所以就异或之后的值是0//res += (0 << i);因为是0所以可以省略,p = song[p][u];//然后让他往不优解那边前进一层。}}return res;//最后返回异或之后的最大值res}public int findMaximumXOR(int[] nums) {N = 3100010;idx = 0;song = new int[N][2];int n = nums.length;for(int i = 0 ; i < n ; i ++ ){add(nums[i]);}int res  = 0;for(int i = 0 ; i < n ; i ++ ){//因为输入的是字符串所以需要转成整形。然后每一次比较res的值谁大,然后将最大值重新赋值给resres = Math.max(res,query(nums[i]));}return res;}
}
import java.io.*;
public class Main{static int N = 3100010,idx = 0;static int[][] song = new int[N][2];//插入public static void add(int x){int p = 0;//从头结点开始for(int i = 30 ; i >= 0 ; i -- ){ //因为每一个数的二进制是有31位组成,所以需要从大开始遍历int u = x >> i & 1;//每一个数的二进制31个二进制每一位看0还是1if(song[p][u] == 0) song[p][u] = ++idx;//判断这一层是空的,就创建,然后赋值下标p = song[p][u];//然后让往下前进一层}}//查询public static int query(int x){int p = 0,res = 0;//从根节点0开始。res进就算异或后的最大值for(int i = 30; i>= 0 ; i --){int u = x >> i & 1;if(song[p][1-u] != 0){ //如果该节点的u是0,则判断一下在这一层有没有跟他相反的0-1,1-0,如果相反对应位置有数res += (1 << i);//res就将该二进制位对应异或之后的最优解1每一位顺次加起来。因为是异或相反数就是1,这是最优解p = song[p][1-u];//然后往最优解那边前进一层。}else{//否则就不是最优解的0匹配1,1匹配0,所以就异或之后的值是0//res += (0 << i);因为是0所以可以省略,p = song[p][u];//然后让他往不优解那边前进一层。}}return res;//最后返回异或之后的最大值res}public static void main(String[] args)throws IOException{BufferedReader re = new BufferedReader(new InputStreamReader(System.in));BufferedWriter wt = new BufferedWriter(new OutputStreamWriter(System.out));int n = Integer.parseInt(re.readLine());String[] s = re.readLine().split(" ");for(int i = 0 ; i < n ; i ++ ){add(Integer.parseInt(s[i]));}int res  = 0;for(int i = 0 ; i < n ; i ++ ){//因为输入的是字符串所以需要转成整形。然后每一次比较res的值谁大,然后将最大值重新赋值给resres = Math.max(res,query(Integer.parseInt(s[i])));}wt.write(res +" ");//最后输出res,因为快输出输出的是字符串,所以需要在后面加上“ ”;wt.close();}
}

9. 并查集 find merge

15. 合并集合

在这里插入图片描述

原题链接
原题链接


import java.util.Scanner;
public class Main{static int N = 100010;static int[] p = new int[N];public static void main(String[] args){Scanner scan = new Scanner(System.in);int n = scan.nextInt(); // 全部有n个数int m = scan.nextInt(); // 读入m个操作//将n个数每个数各自都在一个集合里面。都指向自己,说明现在有多少个集合for(int i = 1 ; i <= n ; i ++) p[i] = i; while(m -- > 0){String s = scan.next();int a = scan.nextInt();int b = scan.nextInt();//合并集合if(s.equals("M")) p[find(a)] = find(b); //将a集合的根节点即祖先指向b集合的祖先 else{ //是否同个集合if(find(a) == find(b))System.out.println("Yes"); //如果两个集合的祖先相同说明两个集合在同个集合中。else System.out.println("No"); //否则相反}}}//并查集的核心操作,寻找根节点祖先 + 路径压缩public static int find(int x){// 如果这个集合的父节点指向的不是自己,说明不是根节点,递归寻找,//最后找到根节点之后,把路径上的所有集合都指向根节点、if(p[x] != x) p[x] = find(p[x]); return p[x]; // 最后返回根节点}
}

16. 连通块中点的数量(每个集合有多少个元素)

在这里插入图片描述

原题链接

import java.util.Scanner;
public class Main{static int N = 100010;static int[] p = new int[N];static int[] size = new int[N];//size用来存每个集合中数的个数public static void main(String[] args){Scanner scan = new Scanner(System.in);int n = scan.nextInt();int m = scan.nextInt();for(int i = 1 ; i <= n ;i ++){p[i] = i;size[i] = 1;// 一开始每个数是一个集合,各自都是个数为1;}while(m -- > 0){String s = scan.next();if(s.equals("C")){int a = scan.nextInt();int b = scan.nextInt();if(find(a) == find(b)) continue; // 这里需要特判一下,如果两个数是同个集合中的数,就结束;else{  size[find(b)] += size[find(a)]; // 只有两个数的根节点,也就是祖先的size值才是有用的,//两个集合中的赋值给另一个祖先的,即赋值给另一个祖先的这个祖先就是合并之后的两个集合的祖先//  b的size[]  +  =a的size[] 因为b是合并之后的新祖先,所以要让b加上被合并的ap[find(a)] = find(b); //合并操作,p[a]的祖先指向b,说明b是合并之后的祖先}}else if(s.equals("Q1")){int a = scan.nextInt();int b = scan.nextInt();if(find(a) == find(b))System.out.println("Yes");else System.out.println("No");}else{int a = scan.nextInt();//只有根节点的size才是有用的,则通过find(a)找到他的根节点然后输出根节点的size;System.out.println(size[find(a)]);}}}public static int find(int x){if(p[x] != x) p[x] = find(p[x]);return p[x];}
}

17. 食物链

原题链接

法一: x,x+n,x+n+n merge(f[x+n],f[x])
思路:

  1. 因为有三种物种,A吃B,B吃C,C吃A
  2. 如果我们用一个数组存储,那么比如1吃2,那么我们让2的角标处的值标记成1,如果3吃2,那怎么标记?一个数组指定标记不过来。
  3. 那么我们想用三个数组存储,其实也存储不过来,因为角标就那么几个,
  4. 最好的方法就是,用x,x+n,x+n+n来表示
    比如1吃2,那么就可能有三种情况,
    A类中的1吃B类的2 : fa[1] = fa[2+n+n]
    B类中的1吃C类的2 : fa[1+n] = fa[2]
    C类中的1中A类的2 : fa[1+n+n] = fa[2+n];
    这样的话,就会有3*n个角标,就可以充分表达
    A中的1吃B中的2(B中的2用2+n表示)
    这样的话就不会出现数字冲突

A吃B
则让f[A] = B

/**/#include <bits/stdc++.h>
using namespace std;
int fa[200000];
int n,m,k,x,y,ans;
int get(int x)
{if(x==fa[x]) return x;return fa[x]=get(fa[x]);
}
void merge(int x,int y)
{fa[get(x)]=get(y);
}
int main()
{cin>>n>>m;for(int i=1;i<=3*n;i++) fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d%d",&k,&x,&y);if(x>n || y>n) ans++;else if(k==1){if(get(x)==get(y+n) || get(x)==get(y+n+n)) //如果x,y是同类,但是x是y的捕食中的动物,或者x是y天敌中的动物,那么错误.ans++;else{merge(x,y);merge(x+n,y+n);merge(x+n+n,y+n+n);}}else{if(x==y || get(x)==get(y) || get(x)==get(y+n)) //x就是y,或者他们是同类,再或者是y的同类中有xans++;//都是假话else{merge(x,y+n+n);//y的捕食域加入xmerge(x+n,y);//x的天敌域加入ymerge(x+n+n,y+n);//x的捕食域是y的同类域.}}}cout<<ans<<endl;
}

法二:将有关系的都存储在一个部落,用到根节点的距离表示关系
二刷总结

  1. X吃Y 让x的祖宗等于y的祖宗 或者 y的祖宗等于x的祖宗都可以
  2. find查找函数中,具有压缩路径的作用,所以在写的时候,先找到此根节点,然后依次压缩,如下代码
    find中 d[x] += d[p[x]];
int find(int x)
{if (p[x] != x){int t = find(p[x]);d[x] += d[p[x]];p[x] = t;}return p[x];
}

不可以如下代码

int find(int x)
{if (p[x] != x){d[x] += d[p[x]];return p[x] = find(p[x]);}return p[x];
}
  1. 在查询合并过程中,比如查询x的父节点,应该用一个变量记录下来,不能多次find,不然找不到x的原来父节点了
  2. 初始化 p[i] = i; d[i] = 0;
  3. 合并的时候,画图即可明白彼此的距离

具体过程如下:

#include <iostream>using namespace std;const int N = 50010;int n, m;
int p[N], d[N];int find(int x)
{if (p[x] != x){int t = find(p[x]);d[x] += d[p[x]];p[x] = t;}return p[x];
}int main()
{scanf("%d%d", &n, &m);for (int i = 1; i <= n; i ++ ) p[i] = i;int res = 0;while (m -- ){int t, x, y;scanf("%d%d%d", &t, &x, &y);if (x > n || y > n) res ++ ;else{int px = find(x), py = find(y);if (t == 1){if (px == py && (d[x] - d[y]) % 3) res ++ ;else if (px != py){p[px] = py;d[px] = d[y] - d[x];}}else{if (px == py && (d[x] - d[y] - 1) % 3) res ++ ;else if (px != py){p[px] = py;d[px] = d[y] + 1 - d[x];}}}}printf("%d\n", res);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/801954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【接口自动化】参数化替换

在做接口测试时&#xff0c;除了测单个接口&#xff0c;还需要进行业务链路间的接口测试 比如[注册-登陆]需要token鉴权的业务流 当我们用使用postman/jmeter等工具时&#xff0c;将注册接口的一些响应信息提取出来&#xff0c;放到登陆接口的请求中&#xff0c;来完成某个业务…

在Gazebo中如何拯救翻车的机器人

Gazebo提供了一些交互工具&#xff0c;允许你直接通过图形界面操作模型&#xff1a; 启动Gazebo后&#xff0c;在右侧工具栏中&#xff0c;你会找到一个可以拖拽物体的图标&#xff08;通常是一个手掌图标或者类似的&#xff09;。点击这个图标。 随后&#xff0c;你可以用鼠标…

Linux/Lame

Lame 今天随便乱逛发现这台机器貌似是 HackTheBox 平台的第一台机器&#xff0c;而且我还没做过&#xff0c;从简介上来看的话是一台很简单的机器&#xff0c;快快的玩一下 Enumeration nmap 首先用 nmap 扫描一下常见的端口&#xff0c;发现系统对外开放了 21,22,139,445 端…

面试算法-160-合并两个有序链表

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 解 class Solution {public ListNode mergeTwoLists(ListNode li…

NineData创始人CEO叶正盛受邀参加『数据技术嘉年华』的技术大会

4月13日&#xff0c;NineData 创始人&CEO叶正盛受邀参加第13届『数据技术嘉年华』的技术大会。将和数据领域的技术爱好者一起相聚&#xff0c;并分享《NineData在10000公里跨云数据库间实时数据复制技术原理与实践》主题内容。 分享嘉宾 叶正盛&#xff0c;NineData CEO …

多线程同步计数器CountDownLatch,CyclicBarrier,Semaphore

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 CountDownLatch CountDownLatch是一个同步工具类,它允许一个或多个线程等…

【学习】软件验收测试,能否选择第三方检测机构进行测试?

随着信息技术的快速发展&#xff0c;软件已经成为各行各业中不可或缺的一部分。为了保证软件的质量和稳定性&#xff0c;验收测试成为了软件开发过程中至关重要的一环。那么&#xff0c;第三方软件测试机构可以做验收测试吗&#xff1f;我们一起来看下今日的分享。 一、验收测…

MySQL操作DML

目录 1.概述 2.插入 3.更新 4.删除 5.查询 6.小结 1.概述 数据库DML是数据库操作语言&#xff08;Data Manipulation Language&#xff09;的简称&#xff0c;主要用于对数据库中的数据进行增加、修改、删除等操作。它是SQL语言的一部分&#xff0c;用于实现对数据库中数…

diffusion model(十五) : IP-Adapter技术小结

infopaperhttps://arxiv.org/pdf/2308.06721.pdfcodehttps://github.com/tencent-ailab/IP-Adapterorg.Tencent AI Lab个人博客地址http://myhz0606.com/article/ip_adapter 1 Motivation 为了对文生图diffusion model进行特定概念的定制&#xff0c;常用LoRA[1]、textual in…

Android Studio 生成 keystore 签名文件及打包验证流程

一、创建keystore签名文件 1、在菜单栏中&#xff0c;依次点击 Build - Generate Signed Bundle/Apk...(生成签名) 2、选择 APK 选项&#xff0c;点击按钮 Next 到下一步 3、新建key store秘钥文件&#xff0c;点击按钮 Next 到下一步 4、按如下提示填写信息&#xff0c;点击按…

JAVA POI Excel 使用数组公式 FREQUENCY

平台及依赖 JAVA 17POI版本 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.5</version></dependency><dependency><groupId>org.apache.poi</groupId><art…

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(四)- 配置和设置指令(vsetvli/vsetivli/vsetvl)

1. 引言 以下是《riscv-v-spec-1.0.pdf》文档的关键内容&#xff1a; 这是一份关于向量扩展的详细技术文档&#xff0c;内容覆盖了向量指令集的多个关键方面&#xff0c;如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量…

蓝桥杯模拟赛练习题—— 燃烧你的卡路里

目标 请在 js/index.js 和 index.html 文件中补全代码&#xff0c;完成以下目标&#xff1a; 点击“定制方案”按钮后&#xff0c;弹出侧滑页面&#xff0c;所使用的组件为 el-drawer&#xff0c;相关属性如下&#xff1a; 参数说明类型默认值v-model是否显示 Drawerboolean…

短视频技术课程在哪学?来这几个资源网站看看,是你需要的

做短视频&#xff0c;有时候就像是做饭&#xff0c;素材好比是食材&#xff0c;没了好食材&#xff0c;怎么做都是不是味儿。今天&#xff0c;我得跟大家好好聊聊&#xff0c;作为一个剪辑界的“老油条”&#xff0c;我是怎样在这个素材的海洋里捞到宝贝的。九才素材网&#xf…

新手养猫必备!福派斯三文鱼益生菌猫粮,让猫咪更健康

亲爱的朋友们&#xff0c;我知道你们中的许多人可能正在考虑养猫&#xff0c;或者刚刚成为了一位猫奴。对于新手来说&#xff0c;选择合适的猫粮可能是一个令人困惑的问题。今天&#xff0c;我想向大家推荐一款非常适合新人的猫粮——福派斯三文鱼益生菌猫粮。 &#x1f43e; 首…

船气废弃锅炉三维仿真vr交互展示降低培训门槛

火化炉是殡葬行业的核心设备&#xff0c;其操作技艺对于专业人才的培养至关重要。然而&#xff0c;传统实践教学受限于时间、场地、设备损耗等多重因素&#xff0c;难以给予学生充分的实操机会。面对这一挑战&#xff0c;我们创新推出了火化炉vr三维仿真培训软件&#xff0c;以…

中颖51芯片学习3. 定时器

中颖51芯片学习3. 定时器 一、SH79F9476定时器简介1. 简介2. 定时器运行模式 二、定时器21. 说明&#xff08;1&#xff09;时钟&#xff08;2&#xff09;工作模式 2. 寄存器&#xff08;1&#xff09;控制寄存器 T2CON&#xff08;2&#xff09;定时器2模式控制寄存器 T2MOD …

[大模型]Baichuan2-7B-chat FastApi 部署调用

Baichuan2 介绍 Baichuan 2 是百川智能推出的新一代开源大语言模型&#xff0c;采用 2.6 万亿 Tokens 的高质量语料训练。在多个权威的中文、英文和多语言的通用、领域 benchmark 上取得同尺寸最佳的效果。 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;…

并行超算云计算使用步骤完整流程详情

本文目录 一、将项目传入并运云。二、创建项目的虚拟环境三、编辑run.sh脚本四、提交作业五、查看作业输出六、查看提交的作业号七、结束作业 一、将项目传入并运云。 二、创建项目的虚拟环境 打开终端 使用conda创建&#xff1a;conda create -n 环境名 python3.8查看conda下…

Java面试必问题29:MySQL篇(重点必问)

数据库的ACID特性 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务中的操作要么全部成功&#xff0c;要么全部失败。事务是一个不可分割的单元&#xff0c;要么全部执行&#xff0c;要么全部回滚。如果事务中的任何操作失败&#xff0c;所有操作都将被回滚到事务开始…