• Currency Editorial


    \[f_l = \max_{i=0}^{l-1} nxt_i \]

    \(f_l\) 表示以 \(l\) 为右端点,最小右端点为 \(f_l\)

    我们不需要动态维护 \(f\) ,而且我也不会维护。考虑合并两块东西,那么会有一些 \(nxt_i\) 被修改。我们令 \(l = i + 1\) ,计算一下以 \(f_l\) ,再计算以 \(f_l\) 为右端点,最大左端点为 \(l_1\)

    \(nxt_{l1}\) 为前缀 \(nxt\) 最大值。可能需要继续计算 \(l = l1 + 1\) 的情况,发现如果 \(nxt_{l1}\) 不是第一次作为前缀最大值被这样计算到,那么在以前这些答案已经被考虑过了。

    因为 \(f_{l1+1}\) 一定不变(为 \(nxt_{l1}\))。中间最大左端点与上一次不一样当且仅当中间有 \(nxt\) 被改动,被改动就被统计过。

    因此每个点被加进来要 \(\log n\) 复杂度统计一遍答案,第一次作为最大值被计算又要花费 \(\log n\) 时间。由于启发式合并,因此只会考虑 \(n \log n\) 个点,因此复杂度为 \(O(n \log^2 n)\)

    #include <map>
    #include <set>
    #include <queue>
    #include <cmath>
    #include <bitset>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define pii pair <int , int>
    #define pll pair <LL , LL>
    #define mp make_pair
    #define fs first
    #define sc second
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    //const int Mxdt=100000; 
    //static char buf[Mxdt],*p1=buf,*p2=buf;
    //#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
    
    template <typename T>
    void read(T &x) {
    	T f=1;x=0;char s=getchar();
    	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s-'0');s=getchar();}
    	x *= f;
    }
    
    template <typename T>
    void write(T x , char s='\n') {
    	if(!x) {putchar('0');putchar(s);return;}
    	if(x<0) {putchar('-');x=-x;}
    	T tmp[25]={},t=0;
    	while(x) tmp[t++]=x%10,x/=10;
    	while(t-->0) putchar(tmp[t]+'0');
    	putchar(s); 
    }
    
    const int MAXN = 1e6 + 5;
    
    int vis[MAXN] , a[MAXN] , n , Q;
    
    int main() {
    	freopen("match.in" , "r" , stdin);
    	freopen("match.out" , "w" , stdout);
    	read(n),read(Q);
    	for (int i = 0; i < n; ++i) read(a[i]);
    	
    	memset(vis , -1 , sizeof vis);
    	for (int i = n - 1; i >= 0; --i) {
    		if(vis[i] == -1) vis[i] = i , vis[(i - a[i] + n) % n] = i;
    	}
    	write(vis[0]);
    	
    	while(Q -- > 0) {
    		int x , y;
    		read(x),read(y);
    		a[x] = y;
    		for (int i = 0; i < n; ++i) vis[i] = -1;
    		for (int i = n - 1; i >= 0; --i) {
    			if(vis[i] == -1) vis[i] = i , vis[(i - a[i] + n) % n] = i;
    		}
    		write(vis[0]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    笛卡尔积
    Oracle语句以及各种知识点
    vue和angular的区别:
    vue的生命周期的理解
    使用递归实现一个数组的快速排序
    对css盒模型的理解
    对 超链接 的理解
    HTML语义化的理解
    HTML 、XHTML、H5的区别:
    mysql的使用相关问题
  • 原文地址:https://www.cnblogs.com/Reanap/p/15913199.html
Copyright © 2020-2023  润新知