ACM's career is over
perm_ identity   query_ builder
list journal   comment 2 comments

It's a pity, orz

Python can live. We've been struggling for a long time
Finally, it saves less than an hour to calculate the interval maximum value of the four node line segment tree
Finally, it collapsed

Iron head baby

But I'm happy... I'm off the list

It can be regarded as the end of more than two years of ACM career with a little regret

It's time to do something you like


SPOJ GSS3 - Can you answer these queries III
perm_ identity   query_ builder
list ACM Road , article   comment 1 comment

Catch fish and write a blog
Qwq does not feel really hard to write half a year

Portal:
SPOJ GSS3 - Can you answer these queries III

Meaning of the title:
Given a set of data, there are multiple operations:
The largest sub segment of the query
2. Modify the data in a location

 1.png

Explanation:
After reading the question, we can find that it is interval query + single point update
For each interval, we can maintain the maximum sum of sub segments, but when pushup is updated, it is hard to handle the merging
Considering the following cases, when the sum of the largest sub segments of the two intervals is merged, it is divided into three cases:
1. The sum of the largest sub segments is in the left interval
2. The sum of the largest sub segments is in the right interval
3. The largest sub segment and the middle part
 2.png
For the first two cases, we can directly take the larger value, and for the third case, special consideration can be given
When the sum of the largest sub segments is between two intervals, it must be composed of the suffix of the left interval and the prefix of the right interval. If you want to make the sum of the sub segments maximum, it must be the maximum suffix of the left interval and the maximum prefix sum of the right interval
 3.png
The maximum sub segment and part are solved. Now we will deal with the prefix sum used to maintain the largest sub segment
Taking prefix sum as an example, there are two cases of maximum prefix sum after merging
1. The maximum prefix sum is in the left range
2. The prefix on the right side of the interval includes the largest part
 4.png
When the first case is handled directly, in the second case, the maximum prefix sum is equal to the sum of the left interval + the maximum prefix sum of the right interval

At this point, we have known all the information to be maintained by the line segment tree
1. Interval sum
2. Maximum prefix sum of interval
3. Maximum suffix sum of interval
4

Based on the above information, we can conclude how to maintain the current node:

 //The update prefix and (left interval prefix or right interval prefix + left interval and) t [cur]. Per = max (t [cur < < 1]. Sum = t [cur < < 1] < 1]. Sum; sum;; / / update prefix and (left interval prefix or right interval prefix + left interval prefix + left interval and) t [cur]. Per = max (t [cur < < 1]. Per, t [cur < 1] < 1]. Sum + T [cur < 1 < 1]. Per);;;;; / / update suffix and (same thing) 
 t [cur [cur or right interval prefix + left interval and) t [cur]; t [cur < < 1]. Sum = t [cur < 1]; sum = t [cur < 1]; sum + T [1]]. Suf = max (t [cur < < 1 | 1]. Suf, t [cur < < 1]. Suf + T [cur < < 1 | 1]. Sum); 
 / / updates the maximum segment sum In the case of the left and right suffixes of T [cur, t] / (T, t] < cur (1); [t] / (T) < cur (1); [cur] / [t] < 1;

Single point update is very good to achieve, and the line tree board is almost

The code is as follows:

Accept C++14 (clang 4.0) 20ms:

 /**
 * @author  Moe_ Sakiya    sakiya@tun.moe
 * @date    2019-07-23 13:19:44
 *
 */

#include <iostream>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

using namespace std;

#define leftSon left,mid, Cur < < 1 define rightson mid + 1, right, cur < < 1| 1
 const int maxn = 50005; 
 struct node {int sum; / / the interval of the current node and 
 int per; / / the maximum prefix of the current node and (the first sub segment and) 
 int suf; / / the maximum suffix of the current node and (the last sub segment and) 
 int con; //T [maxn < 2];; 
; int n, q;;;; / / update update update update (void pushup (int cur) {/ / / / update interval and T [cur]. Sum = t [cur < < 1]. Sum = t [cur < < 1]. Sum + T [cur < < 1]. Sum;; / / update prefix and update prefix and (left or right prefix + left interval prefix + left interval and) 
 t [cur] (cur]. Per]. Sum = t [cur < < 1 < < 1]. Sum;;; / / update prefix update prefix and (left interval prefix or right prefix + left interval prefix + left interval and) t [cur]; t [cur]. Per]. Per / per]. Per / update prefix and (left interval prefix or right prefix + left interval prefix) = max (t [cur < 1]. Per, t [cur < 1]. Sum + T [cur < < 1]. Per); Update the suffix and (the same reason) 
 t [cur]. Suf = max (t [cur < 1 < 1241]; suf, t [cur < < 1 < 1]. Suf, t [cur < < 1 < 1]. Suf + T [cur < < 1 < 1 < 1]. Sum);;;; / / update largest sub segment and two situations 
 / / 1. Separate in left and right interval 
 t [cur]. Con = max (t [cur < < < 1]. Con, t [cur < < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 < 1 <]. Con); 
 / / 2. In the merged interval (left interval suffix + right interval prefix) 
 t [cur]. Con = max (t [cur]. Con, Void builtree (int left, int right, int cur) {int mid = (left + right) {int mid = (left + right) > > 1; < if if (left = = right) {scanf (% d ", & T [cur]. Sum); < T [t [cur]. Sum); 
 t [cur] / suf = t [cur]. Suf = t [cur] / suf = t [cur]. Suf = t [cur]. Saf = t [cur]. Saf = t [cur]. Saf = t [cur]. Saf = t [cur] / saf = t [cur] / saf = t [cur]. Saf = t [cur]. Saf = t = t [cur]. Saf = t per = t [cur]. Con = t [cur]. Sum; 
 return; 
}
 buildtree (leftson); 
 buildtree (rightson); Pushup (cur); 
 pushup (cur); (return; 
 return; 
} 
 / / modify void updatnode (int node, int value, int left, int right, int cur) {int mid = (left + right) > > 1; 
 if (left = = right) {t [cur]. Suf = t [cur]. Per = t [cur]. Get = t [cur]. Com = t [cur]. Com = t [cur]. Sum = value; 
 return; 
 
 
 
 
 (left = = right) {if (left = = right) {t [cur]. Suf = t [cur]; suf = t [cur]. Per = t = t [cur if (node < = mid) 
 updatenode (node, value, leftson); / / query the querysesection (int leftsection, int rightsection, int left, int right, int cur) {int mid = (left + right) > > 1; / / / / / / / / the current node is completely in the query interval 
 if (leftsection < = left & amp & amp; right < = right & amp; right < = right < = right, int right, int cur) {int mid = (left + right) > > 1;; / / the current node is completely in the query interval 
 if (leftsection < = left & amp; right < = right & amp; right < = right < = right < < if (leftsection < = left & amp; right < = right < = right < < if (leftsection < = left & amp & amp; right < = right < < if if if (leftsection < = left & amp; right < = right & amp htsection) 
 return t [cur]; / / the current node does not recurse downward in the query interval 
 if (mid < leftsection) 
 return querysection (leftsection, rightsection, rightson); 
 else if (rightsection < = mid) 
 return querysection (leftsection, rightsection, leftson); / / the current node takes the left and right subtrees in the query area to merge and solve (similar to the push up operation) 
 node retnode, leftnode, rightnode; 
 leftnode = querysection (leftsection, rightsection, leftson); 
 / / merging interval result 
 retnode. Sum = leftnode. Sum + rightnode. Sum; 
    retNode.per = max(leftNode.per, leftNode.sum + rightNode.per);
    retNode.suf = max(rightNode.suf, leftNode.suf + rightNode.sum);
    retNode.con = max(leftNode.con, rightNode.con);
    retNode.con = max(retNode.con, leftNode.suf + rightNode.per);
    return retNode;
}

int main(void) {
    ios::sync_ with_ stdio(false);
    cin.tie(NULL);
    int cmd, l, r;
    scanf("%d", &n);
    BuildTree(1, n, 1);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        scanf("%d %d %d", &cmd, &l, &r);
        switch (cmd) {
        case 0:
            UpdateNode(l, r, 1, n, 1);
            break;
        case 1:
            printf("%d\n", QuerySection(l,  r, 1, n, 1).con);
            break;
        }
    }
    return 0;
}

UVA 294 - Divisors
perm_ identity   query_ builder
list ACM Road , article   comment comment

Supplementary questions
A simple formula problem of number theory

Meaning of the title:
Given an interval, find the number with the largest number of factors in this interval [l, R], and output it and the number of its factors

 1.png

Explanation:
See you for the first time
This problem uses the basic theorem of arithmetic (also known as the unique decomposition theorem of positive integers). That is, for a natural number greater than 1, if it is not a prime number, it must be written as the product of two or more prime numbers, and there is a unique way to write it after permutation from small to large
Therefore, all the numbers in the interval [l, R] are decomposed to get the unique expression, and then the number of factors is calculated
First of all, for 12, there are six factors (1, 12, 2, 6, 3, 4), and its unique expression is: 12 = 2 ^ 2 * 3 ^ 1
For 24, there are eight factors (1, 24, 2, 12, 3, 8, 4, 6), and its unique expression is: 24 = 2 ^ 3 * 3 ^ 1
We can see the law, add 1 to the index of all prime factors in its unique expression, and then take the product, which is the number of factors

The number of factors = the product of exponent + 1 of all prime factors

Speed up the operation by prime number sieve

Accept G++ 530ms:

 /**
 * @author  Moe_ Sakiya    sakiya@tun.moe
 * @date    2018-11-26 18:59:49
 *
 */

#include <iostream>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

using namespace std;

const int maxN = 50005; 

long long int arrPrime[maxN];
bool isPrime[maxN];
int cnt;

void calPrimes() {
    memset(isPrime, 1, sizeof(isPrime));
    cnt = 0;
    isPrime[1] = false;
    for (long long int i = 2; i < maxN; i++) {
        if (isPrime[i] == true)
            arrPrime[cnt++] = i;
        for (int j = 0; j < cnt && i * arrPrime[j] < maxN; j++) {
             isPrime[i * arrPrime[j]] = false;
            if (i % arrPrime[j] == false)
                break;
        }
    }
    return;
}

long long int calNum(int n) {
    long long int ret = 1;
    int num;
    for (int i = 0; i < cnt; i++) {
        if (n % arrPrime[i] == 0) {
            num = 1;
            while (n % arrPrime[i] == 0 && n > 0) {
                 num++;
                n /= arrPrime[i];
            }
            ret *= num;
        }
    }
    return ret;
}

int main(void) {
    ios::sync_ with_ stdio(false);
    cin.tie(NULL);
    long long int maxNum, maxCount;
    int t, l, r;
    calPrimes();
    scanf("%d", &t);
    while (t--) {
        maxNum = 0;
        maxCount = 0;
        scanf("%d %d", &l, &r);
        for (int i = l; i <= r; i++) {
            long long int tmp = calNum(i); 
            if (tmp > maxCount) {
                maxCount = tmp;
                maxNum = i;
            }
        }
        printf("Between %d and %d, %lld has a maximum of %lld divisors.\n", l, r, maxNum, maxCount);
    }
    return 0;
}

Algorithm note | Cantor expansion and its inverse operation
perm_ identity   query_ builder
list algorithm , article   comment comment
Cantor unfolds

Cantor expansion is a bijection permutation to a natural number
For a sequence, all permutations are numbered from small to large according to lexicographic order. The extension is used to calculate the position of this arrangement in its order

Take a chestnut system( °▽° )╯
For the sequence {1,3,2}, its order is in the second position of all permutations, and the former is {1,2,3}

The formula is as follows:
 cantor.png
Where t is the order of its arrangement, a_ I is the I th element in the sequence and N is the total length of the sequence

We can see that we need to calculate n! In this step, we can optimize the time complexity by typing tables. When n! Is too large, we need to calculate large integers

Inverse operation of Cantor expansion

Because Cantor expansion is a bijection, then a legal value of t must correspond to a unique sequence, that is to say, the sequence with the order of t can be calculated reversely

 If the value of cur-1 (cur-1) is used, then the value of cur-1 (cur-1) is used

Let's go straight to the question Codevs 2972 - course selection

But this problem... The data is not very strong... There are only three monitoring points

Reference: Joseph Galante: Generalized Cantor Expansions


HDU 3974 - Assign the task
perm_ identity   query_ builder
list ACM Road , article   comment 3 comments

Aha, I'm sakiya back
Surprise or surprise, surprise or surprise (/ ≥ ▽ ≤)/

This is a simple DFS order + segment tree interval update problem

Meaning of the title:
For an employee in a company, each employee has and has only one direct supervisor, and a boss can have many employees. When assigning tasks to this boss, he will also assign the task to all subordinates (if re assigned, the previous task will be covered). There are two operations for this structure

  • Assign tasks to employees
  • Query the task in progress of the employee

 1.png
 2.png

Explanation:
First, we consider how to represent the state of a subtree
In this way, the task performed by the employee can be known by querying the current parent node (the left end point of the line segment). In this way, a subtree problem is transformed into an interval problem
After that, we will consider the assignment of tasks
Through the interval update of the line segment tree, all nodes under the current node (line segment) are updated and assigned. The time complexity is optimized by using the idea of lazytag

Accept G++ 202ms 4992kB:

 /**
 * @author  Moe_ Sakiya    sakiya@tun.moe
 * @date    2018-11-14 18:46:28
 *
 */

#include <iostream>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

#define leftSon left,mid,curr<<1
#define rightSon mid+1,right, curr<<1|1

using namespace std;

const int maxN = 50005;
struct DisNode
{
    int l, r;
} disArr[maxN];
vector<int> vet[maxN];
int segTree[maxN << 2];
int lazyTag[maxN << 2];
int fatherArr[maxN];
int discnt;

inline void DFS(int id) {
    disArr[id].l = discnt++;
    for (int i = 0; i < (int)vet[id].size(); i++)
        DFS(vet[id][i]); 
    disArr[id].r = discnt - 1;
    return;
}

void pushDown(int curr) {
    if (lazyTag[curr] != -1) {
        lazyTag[curr << 1] = lazyTag[curr];
        lazyTag[curr << 1 | 1] = lazyTag[curr];
        segTree[curr << 1] = lazyTag[curr];
        segTree[curr << 1 | 1] = lazyTag[curr];
        lazyTag[curr] = -1;
    }
    return; 
}

void buildTree(int left, int right, int curr) {
    int mid = (left + right) >> 1;
    if (left == right) {
        segTree[curr] = -1;
        return;
    }
    buildTree(leftSon);
    buildTree(rightSon);
    return;
}

void updateSection(int leftSection, int rightSection, int val, int left, int right,  int curr) {
    int mid = (left + right) >> 1;
    if (leftSection <= left && right <= rightSection) {
        lazyTag[curr] = val;
        return;
    }
    pushDown(curr);
    if (leftSection <= mid)
        updateSection(leftSection, rightSection, val, leftSon);
    if (rightSection > mid)
        updateSection(leftSection, rightSection, val,  rightSon);
    return;
}

int queryNode(int node, int left, int right, int curr) {
    int mid = (left + right) >> 1;
    if (left == right) {
        if (lazyTag[curr] != -1)
            segTree[curr] = lazyTag[curr];
        return segTree[curr];
    }
    pushDown(curr);
    if (node <= mid)
        return queryNode(node, leftSon);
    else
         return queryNode(node, rightSon);
}

int main(void) {
    ios::sync_ with_ stdio(false);
    cin.tie(NULL);
    int t, n, m, arg0, arg1, u, v;
    char ch[10];
    scanf("%d", &t);
    for (int kase = 1; kase <= t; kase++) {
        // INIT
        discnt = 1;
        memset(fatherArr, 0, sizeof(fatherArr));
        memset(vet, 0, sizeof(vet));
        memset(lazyTag, -1, sizeof(lazyTag)); 
        // DataIn
        printf("Case #%d:\n", kase);
        scanf("%d", &n);
        for (int i = 0; i < n - 1; i++) {
            scanf("%d %d", &u, &v);
            fatherArr[u] = v;
            vet[v].push_ back(u);
        }
        // Deal data & Build tree
        for (int i = 1; i <= n; i++)
            if (fatherArr[i] == 0)
                DFS(i);
        buildTree(1, n, 1);
        scanf("%d", &m);
        for (int i = 0; i < m; i++) {
            // Query
            scanf("%s", ch);
            switch (ch[0]) {
            case 'C':
                 scanf("%d", &arg0);
                printf("%d\n", queryNode(disArr[arg0].l, 1, n, 1));
                break;
            case 'T':
                scanf("%d %d", &arg0, &arg1);
                updateSection(disArr[arg0].l, disArr[arg0].r, arg1, 1, n, 1);
                break;
            }
        }
    }
    return 0;
}

  1. one
  2. two
  3. three
  4. four
  5. ...
  6. eleven