CF1039E Summer Oenothera Exhibition 贪心、根号分治、倍增、ST表

时间:2021-09-08 21:07:36

传送门


感谢这一篇博客的指导(Orzwxh)

$PS$:默认数组下标为$1$到$N$

首先很明显的贪心:每一次都选择尽可能长的区间

不妨设$d_i$表示在取当前$K$的情况下,左端点为$i$的所有满足条件的区间中最大的右端点$+1$,然后连边$(i,d_i)$

那么我们就需要求一条链的长度,并支持动态修改某一些边

是不是有些印象?与弹飞绵羊极为相似,没有做过的可以先去感受一下……

上面那道题有两种做法:$LCT$与分块,所以这一道题就衍生出了$O(n\sqrt{n}logn)$的基于$LCT$的做法(安利chd的题解qaq)和$O(n^\frac{5}{3} + n^\frac{4}{3}logn)$的基于分块的做法。下面要谈的是后者。

首先因为输入中$K$的变化是无序的,所以修改会十分麻烦。不妨将询问离线,按照$W-K$从小到大排序,那么$d_i$的改变就是不降的。

设块长为$a$,又设$pre_i$,它需满足$pre_i - i \leq a$、$d_{pre_i} - i > a$、$pre_i$与$i$在同一条链上(如果对于链上的所有点都不满足条件,则令$pre_i=N+1$表示可以直接从$i$点经过不超过一个块长跳出去),维护$cnt_i$表示$i$与$pre_i$之间的点的个数(不计$pre_i$)。

对于每一次查询操作,我们就从$1$开始跳$pre$,每一次都加上对应的$cnt$,那么询问的答案就是$\sum cnt - 1$($1$不需要被算进去)。

但是会发现如果$d_i - i > a$,$pre_i=i$就会死循环,所以我们对与$pre_i=i$的情况使用倍增找到它下一次要跳到哪一个点。

可以知道查询的复杂度是$O(\frac{n}{a}qlogn)$

对于修改,每一个点$i$最多都会被修改$a$次,每一次对于点$i$的修改我们只需要维护$i-a$到$i-1$的$pre$和$cnt$,修改的复杂度就是$O(na^2)$

可知在$a = n^\frac{1}{3}$时该算法取到最小复杂度$O(n^\frac{5}{3} + n^\frac{5}{3}logn)$

喂这个算法和暴力有什么区别啊

可以发现我们的复杂度瓶颈在查询的倍增上,考虑如何优化倍增的复杂度。

因为当$d_i - i > n^\frac{1}{3}$时,前面的所有点的$pre$都是不会因为$d_i$的改变而改变的,所以当$d_i - i > n^\frac{1}{3}$时,单次修改的复杂度变为了O(1)

所以我们可以考虑:当$n^\frac{1}{3} < d_i - i \leq b$时暴力移动$d_i$的值进行更新,当$d_i - i > b$时进行倍增

那么查询的复杂度就变为$O(n^\frac{5}{3} + \frac{n}{b}qlogn)$,修改的复杂度变为了$O(n^\frac{5}{3} + nb)$当$b=n^\frac{2}{3}$时总复杂度取到最小值$O(n^\frac{5}{3} + n^\frac{4}{3}logn)$

然后这道题就做完了

所以这道题的思路就是一个奇怪的与根号分治相似的东西,有点三合一的意思:

①$d_i-i \leq n^\frac{1}{3}$,通过维护$pre_i$与$cnt_i$压缩路径

②$n^\frac{1}{3} < d_i-i \leq n^\frac{2}{3}$,暴力移动$d_i$位置进行更新

③$n^\frac{2}{3} < d_i-i$,倍增找到下一次更新的点

一些实现上的细节:

①在$d_i - i \leq n ^ \frac{1}{3}$部分判断哪一些点需要修改可以使用堆进行维护(再在这里Orzwxh),维护$[i,d_i]$的极差然后扔到堆里面,每一次小于等于当前$W-K$的堆中的点就是需要重新更新$pre$与$cnt$的点

②倍增使用$ST$表进行实现

③维护$n^\frac{1}{3} < d_i - i \leq n^\frac{2}{3}$的部分在计算答案时进行更新即可,不需要额外维护

④根据③,在$d_i - i \leq n ^ \frac{1}{3}$时,不能直接把$pre_i$的贡献算上然后跳到$nxt_{pre_i}$,因为$nxt_{pre_i}$可能还没有更新导致跳到一些奇怪的地方

 #include<bits/stdc++.h>
 #define PII pair < int , int >
 #define st first
 #define nd second
 //This code is written by Itst
 using namespace std;

 inline int read(){
     ;
     char c = getchar();
     ;
     while(!isdigit(c))
         c = getchar();
     while(isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 inline int max(int a , int b){
     return a > b ? a : b;
 }

 inline int min(int a , int b){
     return a < b ? a : b;
 }

 ;
 int N , W , Q , logN , j_small , j_big;
 ][MAXN][] , pre[MAXN] , nxt[MAXN] , nMax[MAXN] , nMin[MAXN] , cnt[MAXN] , len[MAXN] , ans[MAXN];
 bool vis[MAXN];
 priority_queue < PII > q , mod;
 deque < int > v;

 void input(){
     N = read();
     j_small = pow(N , );
     j_big = pow(N , );
     W = read();
     Q = read();
      ; i <= N ; ++i)
         num[i] = ST[][i][] = ST[][i][] = read();
      ; i <= Q ; ++i)
         q.push(PII(read() , i));
 }

 void init(){
      ;  << i <= N ; ++i)
          ; j + ( << i) -  <= N ; ++j){
             ST[i][j][] = min(ST[i - ][j][] , ST[i - ][j + ( << (i - ))][]);
             ST[i][j][] = max(ST[i - ][j][] , ST[i - ][j + ( << (i - ))][]);
         }
     logg2[] = -;
      ; i <= N ; ++i){
         logg2[i] = logg2[i >> ] + ;
         nxt[i] = i + ;
         pre[i] = min(N +  , j_small + i);
         cnt[i] = pre[i] - i;
         nMax[i] = max(num[i] , num[i + ]);
         nMin[i] = min(num[i] , num[i + ]);
         if(i != N)
             mod.push(PII(nMin[i] - nMax[i] , i));
     }
     logN = ;
      <= N)
         logN <<= ;
     logN = logg2[logN];
 }

 void upd(int p , PII t){
     mod.pop();
     while(nxt[p] <= N && nMax[p] - nMin[p] <= t.st && nxt[p] - p <= j_big){
         ++nxt[p];
         if(nxt[p] <= N){
             if(nMax[p] < num[nxt[p]])
                 nMax[p] = num[nxt[p]];
             if(nMin[p] > num[nxt[p]])
                 nMin[p] = num[nxt[p]];
         }
     }
     if(nxt[p] <= N && nxt[p] - p <= j_small)
         mod.push(PII(nMin[p] - nMax[p] , p));
     pre[p] = p;
     cnt[p] = len[p] = ;
     v.clear();
     v.push_back(p);
     vis[p] = ;
     while(pre[p] <= N && nxt[pre[p]] - p <= j_small){
         pre[p] = nxt[pre[p]];
         ++cnt[p];
         v.push_back(pre[p]);
     }
      ; i && i >= p - j_small ; --i)
         if(vis[nxt[i]]){
             while(v.back() - i > j_small)
                 v.pop_back();
             pre[i] = v.back();
             cnt[i] = len[nxt[i]] + v.size();
             len[i] = len[nxt[i]] + ;
             vis[i] = ;
         }
     memset(vis + max(p - j_small , ) ,  , ));
 }

 void work(){
     while(!q.empty()){
         PII t = q.top();
         q.pop();
         t.st = W - t.st;
         while(!mod.empty() && -mod.top().st <= t.st)
             upd(mod.top().nd , t);
          , all = ;
         while(p <= N){
             int cur = nxt[p] - p;
             if(cur <= j_small){
                 all += cnt[p];
                 p = pre[p];
             }
             else{
                 ++all;
                 while(nxt[p] <= N && nMax[p] - nMin[p] <= t.st && cur <= j_big){
                     ++nxt[p];
                     ++cur;
                     if(nxt[p] <= N){
                         if(nMax[p] < num[nxt[p]])
                             nMax[p] = num[nxt[p]];
                         if(nMin[p] > num[nxt[p]])
                             nMin[p] = num[nxt[p]];
                     }
                 }
                 if(cur <= j_big)
                     p = nxt[p];
                 else{
                      , cMin = 1e9;
                      ; --j)
                          << j) -  <= N){
                             ]) , n = min(cMin , ST[j][p][]);
                             if(m - n <= t.st){
                                 cMax = m;
                                 cMin = n;
                                 p +=  << j;
                             }
                         }
                 }
             }
         }
         ans[t.nd] = all;
     }
 }

 void output(){
      ; i <= Q ; ++i)
         printf();
 }

 int main(){
 #ifndef ONLINE_JUDGE
     freopen("in" , "r" , stdin);
     freopen("out" , "w" , stdout);
 #endif
     input();
     init();
     work();
     output();
     ;
 }

CF1039E Summer Oenothera Exhibition 贪心、根号分治、倍增、ST表的更多相关文章

  1. CF1039E Summer Oenothera Exhibition 根号分治,LCT,ST表

    CF1039E Summer Oenothera Exhibition LG传送门 根号分治好题. 可以先看我的根号分治总结. 题意就是给出长度为\(n\)的区间和\(q\)组询问以及一个\(w\), ...

  2. &lbrack;CF1039D&rsqb;You Are Given a Tree&lbrack;贪心&plus;根号分治&rsqb;

    题意 给你\(n\)个点的树,其中一个简单路径的集合被称为\(k\)合法当且仅当树的每个节点最多属于一条路径,且每条路径包含\(k\)个节点.对于每个\(k(k \in [1,n])\),输出最多的\ ...

  3. NOI&period;AC&num;2266-Bacteria【根号分治&comma;倍增】

    正题 题目链接:http://noi.ac/problem/2266 题目大意 给出\(n\)个点的一棵树,有一些边上有中转站(边长度为\(2\),中间有一个中转站),否则就是边长为\(1\). \( ...

  4. 【BZOJ3784】树上的路径 点分治序&plus;ST表

    [BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...

  5. 浅谈 倍增&sol;ST表

    命题描述 给定一个长度为 \(n\) 的序列,\(m\) 次询问区间最大值 分析 上面的问题肯定可以暴力对吧. 但暴力肯定不是最优对吧,所以我们直接就不考虑了... 于是引入:倍增 首先,倍增是个什么 ...

  6. P7599-&lbrack;APIO2021&rsqb;雨林跳跃【二分&comma;倍增&comma;ST表】

    正题 题目链接:https://www.luogu.com.cn/problem/P7599 题目大意 \(n\)棵树,在某棵树上时可以选择向左右两边第一棵比它高的树跳,现在\(q\)次询问从\([A ...

  7. &lbrack;CF1039E&rsqb;Summer Oenothera Exhibition&lbrack;根号分治&plus;lct&rsqb;

    题意 给一个长度为 \(n\) 的序列, \(q\) 次询问,次给一个 \(k_i\) ,问最少将序列划分成多少次,满足每一段的极差不超过\(w−k_i\). \(1 \leq n, q \leq 1 ...

  8. poj 3264 倍增 ST表

    #include<iostream> #include<cmath> using namespace std; ; int a[maxn]; ]; ]; int quick(i ...

  9. 【BZOJ1047】&lbrack;HAOI2007&rsqb;理想的正方形 (倍增ST表)

    [HAOI2007]理想的正方形 题目描述 有一个\(a*b\)的整数组成的矩阵,现请你从中找出一个\(n*n\)的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: ...

随机推荐

  1. &lbrack;LeetCode&rsqb; 14&period; Longest Common Prefix

    Write a function to find the longest common prefix string amongst an array of strings. public class ...

  2. paper 111:图像分类物体目标检测 from RCNN to YOLO

    参考列表 Selective Search for Object Recognition Selective Search for Object Recognition(菜菜鸟小Q的专栏) Selec ...

  3. SIMATIC PCS 7 结构图

  4. H5上传文件

    XMLHttpRequest 在Html5 规范中已经有全新的变化,规定了XMLHttpRequest Level 2规范(目前最新版本)包含下列新的特性: 处理字节流,例如作为上传或者下载的File ...

  5. 【POJ3237】Tree(树链剖分&plus;线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  6. pojg2744找一个最长的字符串x,使得对于已经给出的字符串中的任意一个y,x或者是y的子串,或者x中的字符反序之后得到的新字符串是y的子串。

    http://poj.grids.cn/practice/2744 描述现在有一些由英文字符组成的大小写敏感的字符串,你的任务是找到一个最长的字符串x,使得对于已经给出的字符串中的任意一个y,x或者是 ...

  7. springmvc 之 Controller

    一.简介 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Mo ...

  8. Maven快速使用阿里云的代理maven仓库

    自从开源中国的maven仓库挂了之后就一直在用国外的仓库,慢得想要砸电脑的心都有了.如果你和我一样受够了国外maven仓库的龟速下载?快试试阿里云提供的maven仓库,从此不在浪费生命…… 仓库地址: ...

  9. python 爬虫与数据可视化--matplotlib模块应用

    一.数据分析的目的(利用大数据量数据分析,帮助人们做出战略决策) 二.什么是matplotlib? matplotlib: 最流行的Python底层绘图库,主要做数据可视化图表,名字取材于MATLAB ...

  10. Photoshop Keynote

    [Photoshop Keynote] 1.Tab:隐藏.显示所有面板. 2.Sihft+Tab:隐藏.显示右侧面板. 3.F:全屏切换. 4.选择并遮住: 参考:http://www.51shipi ...