日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

freeswitch 发update sip消息_LeetCode LCP 05——发 LeetCoin

發布時間:2024/7/19 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 freeswitch 发update sip消息_LeetCode LCP 05——发 LeetCoin 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關鍵字:線段樹

歸航return:(Trivial)LeetCode 1354——多次求和構造目標數組?zhuanlan.zhihu.com歸航return:(Trivial) LeetCode 84—柱狀圖中最大的矩形?zhuanlan.zhihu.com

Problem

力扣決定給一個刷題團隊發 LeetCoin 作為獎勵。同時,為了監控給大家發了多少 LeetCoin,力扣有時候也會進行查詢。

該刷題團隊的管理模式可以用一棵樹表示:

  • 團隊只有一個負責人,編號為 1。除了該負責人外,每個人有且僅有一個領導(負責人沒有領導);
  • 不存在循環管理的情況,如 A 管理 B,B 管理 C,C 管理 A。
  • 力扣想進行的操作有以下三種:

  • 給團隊的一個成員(也可以是負責人)發一定數量的 LeetCoin;
  • 給團隊的一個成員(也可以是負責人),以及他/她管理的所有人(即他/她的下屬、他/她下屬的下屬,……),發一定數量的LeetCoin;
  • 查詢某一個成員(也可以是負責人),以及他/她管理的所有人被發到的 LeetCoin 之和。
  • 輸入:

  • N表示團隊成員的個數(編號為1~N,負責人為1);
  • leadership是大小為(N - 1) * 2的二維數組,其中每個元素[a, b]代表b是a的下屬;
  • operations 是一個長度為Q的二維數組,代表以時間排序的操作,格式如下:
  • operations[i][0] = 1: 代表第一種操作,operations[i][1] 代表成員的編號,operations[i][2] 代表 LeetCoin 的數量;

    operations[i][0] = 2: 代表第二種操作,operations[i][1]代表成員的編號,operations[i][2] 代表 LeetCoin 的數量;

    operations[i][0] = 3: 代表第三種操作,operations[i][1] 代表成員的編號;

    輸出:

    返回一個數組,數組里是每次查詢的返回值(發 LeetCoin 的操作不需要任何返回值)。由于發的 LeetCoin 很多,請把每次查詢的結果模 1e9+7 (1000000007)。

    示例 1:

    輸入:N = 6, leadership = [[1, 2], [1, 6], [2, 3], [2, 5], [1, 4]], operations = [[1, 1, 500], [2, 2, 50], [3, 1], [2, 6, 15], [3, 1]] 輸出:[650, 665] 解釋:團隊的管理關系見下圖。 第一次查詢時,每個成員得到的LeetCoin的數量分別為(按編號順序):500, 50, 50, 0, 50, 0; 第二次查詢時,每個成員得到的LeetCoin的數量分別為(按編號順序):500, 50, 50, 0, 50, 15.

    限制:

  • 1 <= N <= 50000
  • 1 <= Q <= 50000
  • operations[i][0] != 3 時,1 <= operations[i][2] <= 5000
  • LCP 05. 發 LeetCoin - 力扣(LeetCode)?leetcode-cn.com

    Solution

    這里的問題就是區間修改,單點查詢,區間查詢,這類問題的正確解答,就是線段樹。但是我們還需要正確地確定一個節點和其后續的所有節點的正確編號,保證節點和其后代在線段樹的下標都是連續的。這個問題的解決方案就是利用樹的遍歷的先序遍歷來進行求解。為此,我們需要維護一個 dfs 時間戳,當我們第一次訪問到這個節點的時候,就對應的是節點的開始時間,完成先序遍歷的遞歸算法完畢返回之后的時間戳,就剛好是節點的對應時間。這種算法稱作 DFS 序。

    C++ 風格的偽代碼如下:

    void dfs(int idx, int& timeStamp){from[idx] = timeStamp;for (int next : adj[idx]){++timeStamp;dfs(next, timeStamp);}to[idx] = timeStamp; }

    當然,這里需要考慮下標問題,因此實際的實現中,我是將所有的坐標都減去 1,這樣就可以映射到

    中,使用一個大小為 n 的數組即可。在這么處理之后,操作 1 對應的就是在 [from[people], from[people]] 單點修改,2 對應的就是 [from[people], to[people]] 上區間修改,操作 3 對應的就是在 [from[people], to[people]] 上區間查詢。起始時間點設定為 0,這樣可以方便處理后續線段樹的代碼問題。

    上述 test case 中,from 和 to 數組就是:

    from: [0,1,2,5,3,4] 和 to: [5,3,2,5,3,4]

    這么做之前,我們還需要維護一個臨接表,用于這個 dfs 操作:

    vector<vector<int>> generateAdj(const vector<vector<int>>& leadership, int n){vector<vector<int>> adj(n);for (const auto & x : leadership){int src = x[0] - 1;int dst = x[1] - 1;adj[src].emplace_back(dst);}return adj; }

    注意,線段樹的底層原理我并不是很懂,所以不會詳細解釋線段樹的代碼原理,而是當作黑箱子直接使用。代碼如下:

    class Solution {private int[] from;private int[] to;private List<Integer>[] adj;private int cnt;private static final int mod = (int)(1e9 + 7);public int[] bonus(int n, int[][] leadership, int[][] operations) {from = new int[n];to = new int[n];adj = new List[n];cnt = 0;int people = 0;int money = 0;for (int i = 0; i < n; ++i){adj[i] = new ArrayList<>();}for (int[] x : leadership){int src = x[0] - 1;int dst = x[1] - 1;adj[src].add(dst);}dfs(0);List<Integer> ans = new ArrayList<>();SegmentTree segmentTree = new SegmentTree(n);for (int[] operation : operations){switch (operation[0]){case (1):{people = operation[1] - 1;money = operation[2];segmentTree.update(from[people], from[people], money);break;}case (2):{people = operation[1] - 1;money = operation[2];segmentTree.update(from[people], to[people], money);break;}case (3):{people = operation[1] - 1;ans.add((int)(segmentTree.query(from[people], to[people]) % mod));break;}}}return ans.stream().mapToInt(i -> i).toArray();}private void dfs(int idx){from[idx] = cnt;for (int next : adj[idx]){++cnt;dfs(next);}to[idx] = cnt;} } class SegmentTree{private static class SegmentTreeSupport{private SegmentTreeSupport(){}public static int getLeftSon(int x){return x << 1;}public static int getRightSon(int x){return (x << 1) + 1;}public static int getFather(int x){if (x == 0){throw new IllegalArgumentException();}return x >> 1;}public final static int SEGMENT_TREE_FACTOR = 4;}private long[] tree, lazy;private final int length;private void rangeCheck(int index){if (index < 0 || index >= length){throw new IndexOutOfBoundsException(index);}}public SegmentTree(final int[] arr){if (arr == null || arr.length == 0){throw new IllegalArgumentException();}length = arr.length;tree = new long[SegmentTreeSupport.SEGMENT_TREE_FACTOR * length];lazy = new long[SegmentTreeSupport.SEGMENT_TREE_FACTOR * length];buildTree(arr, 0, length - 1, 1);}public SegmentTree(int n){this(new int[n]);}private void buildTree(final int[] arr, int fromIndex, int toIndex, int treeIndex){if (fromIndex == toIndex){tree[treeIndex] = arr[fromIndex];return;}int midIndex = (fromIndex + toIndex) >>> 1;buildTree(arr, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex));buildTree(arr, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex));collectSubMsgTo(treeIndex);}private void collectSubMsgTo(int treeIndex){//this line should be replaced by the function we want to maintain//that is: tree[treeIndex] = f(tree[leftIndex], tree[rightIndex])//if we want to maintain the range sumtree[treeIndex] = tree[SegmentTreeSupport.getLeftSon(treeIndex)] + tree[SegmentTreeSupport.getRightSon(treeIndex)];//if we want to maintain the minimum value // tree[treeIndex] = Math.min(tree[SegmentTreeSupport.getLeftSon(treeIndex)], tree[SegmentTreeSupport.getRightSon(treeIndex)]);//if we want to maintain the maximum value // tree[treeIndex] = Math.max(tree[SegmentTreeSupport.getLeftSon(treeIndex)], tree[SegmentTreeSupport.getRightSon(treeIndex)]);}private void getLazyStatus(int fromIndex, int toIndex, int treeIndex, long diff){//this line should be replaced by the function we want to maintain//now, we set the value to diff // lazy[treeIndex] = diff; // tree[treeIndex] = (long)(toIndex - fromIndex + 1) * diff;//if we want to add the value by diff, then code is:tree[treeIndex] += diff * (toIndex - fromIndex + 1);lazy[treeIndex] += diff;//if we want to set the value and maintain the minimum/maximum value // tree[treeIndex] = diff; // lazy[treeIndex] = diff;//if we want to add the value and maintain the minimum/maximum value // tree[treeIndex] += diff; // lazy[treeIndex] += diff;}private void push_down(int fromIndex, int toIndex, int treeIndex){int midIndex = (fromIndex + toIndex) >>> 1;getLazyStatus(fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex), lazy[treeIndex]);getLazyStatus(midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex), lazy[treeIndex]);lazy[treeIndex] = 0;}public void update(int updateFromIndex, int updateToIndex, long diff){rangeCheck(updateFromIndex);rangeCheck(updateToIndex);update(updateFromIndex, updateToIndex, 0, length - 1, 1, diff);}private void update(int updateFromIndex, int updateToIndex, int fromIndex, int toIndex, int treeIndex, long diff){if (updateFromIndex <= fromIndex && toIndex <= updateToIndex){getLazyStatus(fromIndex, toIndex, treeIndex, diff);return;}if (lazy[treeIndex] != 0){push_down(fromIndex, toIndex, treeIndex);}int midIndex = (fromIndex + toIndex) >>> 1;if (updateFromIndex <= midIndex){update(updateFromIndex, updateToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex), diff);}if (updateToIndex >= midIndex + 1){update(updateFromIndex, updateToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex), diff);}collectSubMsgTo(treeIndex);}public long query(int queryFromIndex, int queryToIndex){rangeCheck(queryFromIndex);rangeCheck(queryToIndex);if (queryFromIndex > queryToIndex){throw new IllegalArgumentException();}return query(queryFromIndex, queryToIndex, 0, length - 1, 1);}private long query(int queryFromIndex, int queryToIndex, int fromIndex, int toIndex, int treeIndex){if (queryFromIndex <= fromIndex && toIndex <= queryToIndex){return tree[treeIndex];}int midIndex = (fromIndex + toIndex) >>> 1;if (lazy[treeIndex] != 0){push_down(fromIndex, toIndex, treeIndex);}//if we want to maintain the range sumreturn (queryFromIndex <= midIndex ?query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)): 0)+ (queryToIndex >= midIndex + 1? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) :0);//if we want to maintain the minimum value // return Math.min( // (queryFromIndex <= midIndex ? query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)) : Long.MAX_VALUE), // (queryToIndex >= midIndex + 1 ? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) : Long.MAX_VALUE) // );//if we want to maintain the maximum value // return Math.max( // (queryFromIndex <= midIndex ? query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)) : Long.MIN_VALUE), // (queryToIndex >= midIndex + 1 ? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) : Long.MIN_VALUE) // );}@Overridepublic String toString() {return "SegmentTreen" +"tree = " + Arrays.toString(tree) +", lazy = " + Arrays.toString(lazy);} }

    時間復雜度上,建立線段樹和 DFS 的過程:

    ,每次查詢的時間復雜度: ,總共有 次查詢,因此總的時間復雜度是: 。

    空間復雜度上,線段樹加上 lazy 標記需要 8 倍的空間,from 和 to 是 1 倍的空間,因此是

    EOF。

    總結

    以上是生活随笔為你收集整理的freeswitch 发update sip消息_LeetCode LCP 05——发 LeetCoin的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。