题面

传送门

题解

为什么大佬们全都是乱搞的……莫非这就是传说中的暴力能进队,乱搞能AC……

似乎有位大佬能有纯暴力+玄学优化\(AC\)(不算上\(uoj\)的\(Hack\)数据的话……这要是放到考场上就是切题的啊……)

整体思路呢,就是我们开一个线段树,线段树上的每一个区间维护“以这个区间右端点为结尾有可能成为后缀最小值的位置”

怎么合并呢

首先右儿子的所有节点都是可以加入的,因为它们后面也没有加上什么东西

然后对于左儿子来说它们相当于后面被整体怼了一个串,我们就要考虑它们是不是仍有可能成为后缀最小值了

首先比较两个位置的字典序大小,我们记\(u\)表示\(s[u,r]\),\(v\)表示\(s[v,r]\),假设\(u\)比\(v\)长,如果\(v\)不是\(u\)的前缀那么它们已经比较出了字典序大小,两个中肯定可以扔掉一个

然而如果\(v\)是\(u\)的前缀,事情就会变得比较辣手了

先给出结论:如果\(v\)是\(u\)的前缀,\(v\)就没有用了

为啥嘞?

因为它们都来自当前区间的左儿子,那么\(v\)的长度最短是\(r-mid+1\),\(u\)的长度最长是\(r-l+1\),根据我们正常线段树的写法\(v\)的长度绝对大于\(u\)的长度的一半

因为\(v\)的长度大于\(u\)的一半,同时\(v\)既是\(u\)的前缀也是它的后缀,那么我们发现\(u\)必定是一个有周期串,而且右儿子中至少有一个周期的开头\(w\)

所以现在\(w\)的字典序比它更小

那么加上新的字符之后\(v\)有没有可能变成后缀最小值呢?

答案是否定的,如果加的字符就是周期串上该有的字符,\(w\)比\(v\)小,如果加的字符小于该有的字符,\(w\)还是比\(v\)小,如果加的字符大于该有的字符,\(u\)就比\(v\)小,所以\(v\)无论如何都不可能再作为后缀最小值了

也就是说这个区间会把右儿子全都加上来,左端点最多加一个,那么一个节点上存的位置最多不会超过\(O(\log n)\)

所以我们只需要能在线段树上维护区间加以及判断字典序就行了

先说正解吧,判断字典序可以二分加哈希找到最后一个相等的位置再判断下一位的大小,不过我们要在区间加的状况下维护哈希值很困难,这样的话我们得把哈希值分块,一次修改就是\(O(\sqrt{n})\)了

正解的代码……去看\(shadowice\)巨巨的吧……才不是因为太长了不想打呢

于是这里区间加直接暴力,判断字典序也直接暴力……似乎是因为数据太水所以可以过……

而且我看了看\(uoj\)上这题排名前几的好像全都是打暴力的……跑得比正解快啊……

代码抄kcz的

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
inline int getop(){R char ch;while((ch=getc())>'9'||ch<'0');return ch-'0';}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
int s[N],n,q;
inline int cmp(const int &a,const int &b,const int &r){
fp(i,0,r-max(a,b))if(s[a+i]!=s[b+i])return s[a+i]<s[b+i]?-1:1;
return 0;
}
struct node{
node *lc,*rc;int pos[21],cnt,l,r;
inline void ins(R int x){pos[++cnt]=x;}
void upd(){
fp(i,1,rc->cnt)pos[i]=rc->pos[i];
cnt=rc->cnt;
fp(i,1,lc->cnt)
while(233){
int t=cmp(lc->pos[i],pos[cnt],r);
if(t>0)break;
if(!t){
(((r-pos[cnt]+1)<<1)>r-lc->pos[i]+1)?--cnt:0,
pos[++cnt]=lc->pos[i];
break;
}
if(!--cnt){
pos[++cnt]=lc->pos[i];
break;
}
}
}
}pool[N<<2],*rt;
int tot,ql,qr,res,d;
inline node* newnode(){return &pool[tot++];}
void build(node* &p,int l,int r){
p=newnode(),p->l=l,p->r=r;
if(l==r)return p->ins(l),void();
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
p->upd();
}
void update(node* p){
if(ql<=p->l&&qr>=p->r)return;
if(ql<=p->lc->r)update(p->lc);
if(qr>p->lc->r)update(p->rc);
p->upd();
}
void query(node* p){
if(ql<=p->l&&qr>=p->r){
R int i=1;!res?res=p->pos[i++]:0;
for(;i<=p->cnt;++i)cmp(p->pos[i],res,qr)<0?res=p->pos[i]:0;
return;
}
if(qr>p->lc->r)query(p->rc);
if(ql<=p->lc->r)query(p->lc);
}
int main(){
// freopen("testdata.in","r",stdin);
// freopen("qwq.out","w",stdout);
n=read(),q=read();
fp(i,1,n)s[i]=read();
build(rt,1,n);
while(q--)if(getop()&1){
ql=read(),qr=read(),d=read();
if(qr-ql+1<=(n>>1))fp(i,ql,qr)s[i]+=d;
else{
fp(i,1,ql-1)s[i]-=d;
fp(i,qr+1,n)s[i]-=d;
}
update(rt);
}else{
ql=read(),qr=read(),res=0;
query(rt),print(res);
}
return Ot(),0;
}

洛谷P5211 [ZJOI2017]字符串(线段树+乱搞)的更多相关文章

  1. 【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)

    Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...

  2. 洛谷题解P4314CPU监控--线段树

    题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...

  3. 洛谷P3372/poj3468(线段树lazy_tag)(询问区间和,支持区间修改)

    洛谷P3372 //线段树 询问区间和,支持区间修改 #include <cstdio> using namespace std; struct treetype { int l,r; l ...

  4. 洛谷P4065 [JXOI2017]颜色(线段树)

    题意 题目链接 Sol 线段树板子题都做不出来,真是越来越菜了.. 根据题目描述,一个合法区间等价于在区间内的颜色没有在区间外出现过. 所以我们可以对于每个右端点,统计最长的左端点在哪里,刚开始以为这 ...

  5. 洛谷P5111 zhtobu3232的线段树

    题意:给定线段树,上面若干个节点坏了,求能表示出多少区间. 区间能被表示出当且仅当拆出来的log个节点都是好的. 解:每个区间在最浅的节点处计算答案. 对于每个节点维护从左边过来能有多少区间,从右边过 ...

  6. 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay

    正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...

  7. 题解——洛谷P2781 传教(线段树)

    可以说是数据结构学傻了的典型案例了 昨天跳到这题上 然后思考了一下 噫!好!线段树裸题 然后打完板子,发现\(  n \le 10^9 \) 显然线段树直接做不太行 然后这题又只有普及的难度 然后我就 ...

  8. 洛谷P4198 楼房重建(线段树)

    题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...

  9. 2018.08.16 洛谷P1471 方差(线段树)

    传送门 线段树基本操作. 把那个方差的式子拆开可以发现只用维护一个区间平方和和区间和就可以完成所有操作. 同样区间修改也可以简单的操作. 代码: #include<bits/stdc++.h&g ...

随机推荐

  1. tomcat https

    转自 http://11lingxian.iteye.com/blog/1491607 双向认证: 客户端向服务器发送消息,首先把消息用客户端证书加密然后连同时把客户端证书一起发送到服务器端, 服务器 ...

  2. 【LA11248 训练指南】网络扩容【最大流】

    题意: 给定一个有向网络,每条边均有一个容量.问是否存在一个从点1到点N,流量为C的流.如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流? 分析: 先跑一遍最大流,如果最大流大于等于C,则输 ...

  3. linux系统中的命令替换与整数运算$(),$(())

    一.$()与`` 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换(command substitution)用的. 所谓的命令替换与我们第五章学过的变量替换差不多, ...

  4. scanf是怎么从标准输入读取数据的

    scanf是从标准输入读取数据的 假设现在标准输入中的数据是123456 int a; 而我scanf("%d",&a); 会把123456转化为数字然后存入到a中. 如果 ...

  5. code1068 乌龟棋

    暴力显然不行,所以考虑dp 记f[i][j][k][l]为使用i张1,j张2,k张3,l张4所得到的最大分数. 对于每个f[i][j][k][l],都可以由i-1张1,j张2,k张3,l张4所得到, ...

  6. Python2.7.9 编码问题

    最近学一学网络爬虫,遇到第一件头疼的事情就是编码问题, 看了很多教程讲得不清楚, 现在整理一下,希望以后查看方便一些 使用   sys.getdefaultencoding()   查看Python的 ...

  7. sklearn中的随机森林

    阅读了Python的sklearn包中随机森林的代码实现,做了一些笔记. sklearn中的随机森林是基于RandomForestClassifier类实现的,它的原型是 class RandomFo ...

  8. Python 2.6 安装wxPython后提示"64.....32"错误解决办法

    ImportError: /usr/local/lib/wxPython-unicode-2.8.10.1/lib/python2.6/site-packages/wx-2.8-mac-unicode ...

  9. [GO]runtime包及gosched的使用

    Gosched:让出CPU时间片 Goexit:退出当前的协程 GOMAXPROCS:设置使用最大的CPU数量(哇,牛逼了...) package main import ( "fmt&qu ...

  10. FCKEditor2.x整合教程-Xproer.WordPaster

    版权所有 2009-2017 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webplug/wordpa ...