Блог пользователя gen

Автор gen, 6 лет назад, перевод, По-русски
Tutorial is loading...
Tutorial is loading...
Tutorial is loading...
  • Проголосовать: нравится
  • +101
  • Проголосовать: не нравится

»
6 лет назад, скрыть # |
Rev. 3  
Проголосовать: нравится +137 Проголосовать: не нравится
  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    How do you use so many functions and manage to get under the TLE?

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +25 Проголосовать: не нравится

      The time complexity of your code has little to do with the number of functions one uses. You should look up basic algorithm complexity analysis (say, an intro to Big O notation) to be introduced to analyzing the runtime complexity of a program.

  • »
    »
    6 лет назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится +6 Проголосовать: не нравится

    Sorry to disturb you,but could you explain how LCT in problem C worked.I do not understand your solution.

    I compute the longest suffix of edge which can form a bipartite firstly,and then I try to add edge from prefix and remove the edge in the suffix to compute the array $$$Last$$$(the same as the $$$last[]$$$ in the tutorial).but it doesn't work,because some circle is ignored(maybe in these cycles,there is a circle of odd length).

    Thank you very much.

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +6 Проголосовать: не нравится

      First I concatenate the edges array with itself, doubling its length. For each $$$l\in [0,M-1]$$$ I compute the max $$$r$$$ such that edges $$$l\ldots r$$$ are bipartite. Maintain the maximum spanning tree of edges $$$l\ldots r$$$ (where the weight of an edge is just its index).

      • When you increment $$$l$$$, you remove edge $$$l$$$ only if it is currently present in the spanning tree.
      • When you increment $$$r$$$, you add edge $$$r$$$ to the spanning tree and remove the edge of minimum weight along the path between the two endpoints of edge $$$r$$$ if they were previously connected.

      You should check the editorial for the other problem I linked if what I said about maintaining the MST doesn't make sense. :)

»
6 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится +22 Проголосовать: не нравится

How do we maintain DSU for C to check if graph is bipartite?

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +17 Проголосовать: не нравится

    Initially set all to the same color.

    Let's say we want to add an edge from $$$u$$$ to $$$v$$$. Check if $$$u$$$ and $$$v$$$ are of the same parent(Are connected). If they are, then make sure their colors are different.

    If they have different parents, Let's say $$$p$$$ and $$$q$$$ respectively, add an edge from $$$q$$$ to $$$p$$$ in the DSU(parent[q] = p). If their colors are the same, you want an additional mark on the edge which says to reverse the color.

    When you want to get the color, go through all the edges leading to the parent, and change the color as you go along the edges if you need to reverse the color.

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +8 Проголосовать: не нравится

    Look here

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +5 Проголосовать: не нравится

In problem C in subtask $$$4$$$ there is $$$l_i \leq 500$$$ in editorial but $$$l_i \leq 200$$$ in the problem statement. Which variant is correct?

»
6 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится -8 Проголосовать: не нравится

In problem A, subtask 3, 2*sqrt(1000) = 2 * 33 = 66, and 66 > 64, the limit of querys in that problem, so, 2*sqrt(n) is ok?, why?, i know that you can use that solution 3 times and get 3*cubic_root(n) which is good enough (it uses 30 querys or something like that), but is more hard to code, and it has a lot of case handiling. UPD: Sorry, sqrt(1000) <= 32

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +18 Проголосовать: не нравится

For Joker subtask 5, I think the post should say:

If we choose $$$B = M \div \sqrt{Q}$$$ we get the following runtime:

(rather than $$$B = M \sqrt{Q}$$$)

otherwise the numbers don’t add up. $$$B$$$ is the block size, and there are $$$M \div B$$$ blocks. The total number of operations is $$$M$$$ per block for the right pointer + $$$QB$$$ in total for the left pointer = $$$M^2 \div B + QB$$$ in total. Equating the two terms so that neither dominates the other gives $$$B = M \div \sqrt{Q}$$$.


And to expand slightly on the algorithm: at the start of each block, initialize DSU with all edges to the left of the block’s leftmost edge. Sort queries by $$$r$$$ in descending order. For each query, add the new edges on the right, then add the appropriate edges on the left, answer the query, and immediately roll back all of those left edges, so that once again the left pointer is at the very start of the block. Don’t bother trying to remove individual left edges (and struggling to do it without also rolling back right edges): just remove them all after each query.

  • »
    »
    6 лет назад, скрыть # ^ |
    Rev. 6  
    Проголосовать: нравится 0 Проголосовать: не нравится

    Further, I think it should be possible to use path compression to improve the complexity somewhat, although I’m not sure it will help in practice.

    The original reason for the $$$\log N$$$ factor is that path compression is not performed in the DSU because it “is impossible” with rollbacks. Of course, there’s nothing preventing one from implementing rollbacks of path compression, but the question is whether it such revertible path compression actually improves efficiency.

    I can’t answer that. But for this particular problem, we can still improve the complexity by using path compression in a part of the solution that doesn’t require rollbacks:

    Notice that the DSU operations corresponding to the right-hand-side edges are not disturbed by any rollbacks. (When a new block starts, we can rebuild the whole DSU from scratch. It is not necessary to roll back the previous block’s right-hand-side operations.) There are $$$M$$$ unions per block from the right-hand side. We can do those unions with path compression, for a total run-time of $$$M \alpha(N)$$$. Assuming revertible path compression is meaningless, we can do the left-hand-side operations without further path compression, at $$$\log N$$$ time per operation. The total time is then $$$M^2 \div B\, \alpha(N) + Q B \log N$$$ (down from $$$(M^2 \div B + Q B) \log N$$$), and equating the two terms to ensure neither dominates the other gives optimal $$$B = M \div \sqrt{Q \frac{\log N}{\alpha(N)}} \approx M \div \sqrt{Q \log N}$$$ with the grand total run-time $$$\mathrm{O}\left(\mathrm{sort}\ Q + M \sqrt{Q\, \alpha(N) \log N}\right)$$$.

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +3 Проголосовать: не нравится

      You can do the LHS operations with path compression too, making the complexity $$$M\sqrt Q\alpha(N)$$$.

      Spoiler (71 pts)
  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +3 Проголосовать: не нравится

    Thanks, fixed!

»
6 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Can someone explain the strategy when k is odd, in Problem A? thx

»
5 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

"the graph exluding..."——you missed a 'c'.(excluding)

»
4 месяца назад, скрыть # |
 
Проголосовать: нравится +7 Проголосовать: не нравится

I am 6 years late but Benq is still alive so maybe I will get a respond

in problem C subtask 5, how do you do Mo's algo with dsu with rollbacks?

as lets say I am in some block the right pointer will move to the right (probably in this problem to the left is better so you can add the edges). but the left pointer goes all over the block, so lets say my right pointer went a lot to the left, O(m) and my left pointer went to the right, so I add edges. then my right pointer goes left again O(m) and my left pointer wants to also go left, I can only pop the last operation so I will have to pop all the progress of the right pointer just to get to the left's operation.

my point is that I might need to rollback some of the right pointer movement to get to the left one operation, but this is bad as the right one operation can be O(m)

example

left operation (need to rollback), right operation, right operation ... how do I handle this cases, I hope I am somewhat clear

»
4 месяца назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

In the subtask of N<=1e9 in problem A, when k is even, you said that the last possible difference is either 2x or 2x-2, and then you can make a jump of length 2x-1 always, this is not true, suppose the last two numbers where 2x, 2, such that x=j, then their difference is 2x-2 but 2+2x > k