题意大概是给你一个字符串,1e5次修改,每次给一个区间升序排列或降序排列,最后输出这个字符串;

其实是个挺裸的线段树优化题;但是我没有意识去结合桶排,扑该.....

首先 1.40分算法

O(NMlogN)

 inline void update(int k){
for(int i=;i<=;++i){
tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
}
} void ud(int k,int l,int r,int L,int R){
if(L<=l&&r<=R)return void();
if(L<=mid)ud(ls,l,mid,L,R);
if(R>mid)ud(rs,mid+,r,L,R);
update(k);

直接sort

 #include<bits/stdc++.h>
using namespace std;
#define val(x) (x-'a'+1)
int s[],N,M;
char S[];
bool cmp1(int a,int b){return a<b;}
bool cmp0(int a,int b){return a>b;}
int main()
{
//freopen("da.in","r",stdin);
// freopen("ac.out","w",stdout);
scanf("%d%d",&N,&M);
scanf("%s",S+);
for(int i=;i<=N;++i)s[i]=val(S[i]);
for(int i=,l,r,opt;i<=M;++i){
scanf("%d%d%d",&l,&r,&opt);
if(!opt)sort(s+l,s+r+,cmp0);
else sort(s+l,s+r+,cmp1);
// if(clock()>999900)break;
}
char c;
for(int i=;i<=N;++i){
c=s[i]+'a'-;
printf("%c",c);
}
printf("\n");
}

其次 2.仍是40分算法:

其实也是出题人没良心,我们可以直接桶排,复杂度O(NM);起码降下了一个log,但还是40分;

代码就不提供了;

最后 3.100分算法:

思路:结合2.中的桶排思想,我们发现修改排序一次可以只有O(N)的复杂度,而N,M<=1e5,自然想到线段树优化桶排;

而这样想的裸想法的复杂度是O(MNlogN)氧化钙!跟暴力一样!

但是可以发现 你的数值N的值域是你的字母,那N就只有26啦;

最后O(MlogN*26)

分析一下  M是询问;  logN是线段树上的查询(合并桶而需查询你所修改的区域的桶来合成一个新的桶); 26是每次桶合并所需复杂度;

好,接下来,我们每次修改一个区间进行排序,就是把对应区间的桶合并成一个新桶,然后用这个新桶进行区间修改,但是注意,这个区间修改一定不要去真的O(N)区间赋值

那就成为了真正的O(NMlogN)了;

那怎么办?

我们可以打懒标记啊!别说你像我一样不会打标记......

那我们就可以标记哪个区间被修改了然后访问到再down一下,最后一遍dfs来一次全down统计答案对吧;

注意,这里down很长很长

 void down(int k){
if(!tmp[k].lazy)return ;
register int sz=len(ls),pl=,pr=;
memset(tmp[ls].tong,,sizeof(tmp[ls].tong));
memset(tmp[rs].tong,,sizeof(tmp[rs].tong));
if(tmp[k].opt){
for(int i=;i<=;++i){
if(tmp[k].tong[i]<=sz)
{
tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
}
else {
tmp[ls].tong[i]=sz;sz=i;break;
}
}
tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
if(len(rs)==&&tmp[rs].tong[sz]==){pr=sz;}
register int zs=len(rs)-tmp[rs].tong[sz];
for(int i=sz+;i<=;++i){
tmp[rs].tong[i]=tmp[k].tong[i];
zs-=tmp[k].tong[i];
if(!zs)break;
}
}
else {
for(int i=;i>=;--i){
if(tmp[k].tong[i]<=sz)
{
tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
}
else {
tmp[ls].tong[i]=sz;sz=i;break;
}
}
tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
register int zs=len(rs)-tmp[rs].tong[sz];
for(int i=sz-;i>=;--i){
tmp[rs].tong[i]=tmp[k].tong[i];
zs-=tmp[k].tong[i];
if(!zs)break;
}
}
if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=;
else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=;
else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
tmp[k].lazy=;tmp[k].opt=;
}

当然我不像Deepin某一样缩行;

其实这里的down就是把你线段树上这个节点的两个儿子所对应区间的桶重新赋值的过程,当然赋值一次需要O(52);

Tip:

还有一点特别容易错的就是

记住每次把你对应修改的区间的桶合并后要立即修改对应区间的桶(区间修改):(这里lg这个vector存放的是你修改的区间的在线段树上的节点编号)

 void exch(int opt){
sort(lg.begin(),lg.end(),cmp);
for(int i=,sz,tt=,ts=;i<lg.size();++i){
sz=len(lg[i]);
memset(tmp[lg[i]].tong,,sizeof(tmp[lg[i]].tong));
if(opt){
for(;tt<=;++tt){
if(sz>=ans[tt]){
sz-=ans[tt];
tmp[lg[i]].tong[tt]=ans[tt];
}
else {
tmp[lg[i]].tong[tt]=sz;
ans[tt]-=sz;break;
}
}
}
else {
for(;ts>=;--ts){
if(sz>=ans[ts]){
sz-=ans[ts];
tmp[lg[i]].tong[ts]=ans[ts];
}
else {
tmp[lg[i]].tong[ts]=sz;
ans[ts]-=sz;break;
}
}
}
}
}

区间修改

然后修改完后要立即把你这些修改的区间到根update一遍,毕竟你的懒标记只能维护儿子而不能维护父亲;

 inline void update(int k){
for(int i=;i<=;++i){
tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
}
} void ud(int k,int l,int r,int L,int R){
if(L<=l&&r<=R)return void();
if(L<=mid)ud(ls,l,mid,L,R);
if(R>mid)ud(rs,mid+,r,L,R);
update(k);
}

update

然后附上代码

 #include<bits/stdc++.h>
using namespace std;
#define val(x) (x-'a'+1)
#define mid (l+r>>1)
#define ls (k<<1)
#define rs (k<<1|1)
#define len(x) (tmp[x].r-tmp[x].l+1)
int s[],N,M;
char S[];
struct node{
int l;int r;
int tong[];
int lazy,lz,opt;
}tmp[<<];
int ans[];
vector<int>lg; inline void update(int k){
for(int i=;i<=;++i){
tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
}
} void down(int k){
if(!tmp[k].lazy)return ;
register int sz=len(ls),pl=,pr=;
memset(tmp[ls].tong,,sizeof(tmp[ls].tong));
memset(tmp[rs].tong,,sizeof(tmp[rs].tong));
if(tmp[k].opt){
for(int i=;i<=;++i){
if(tmp[k].tong[i]<=sz)
{
tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
// if(len(ls)==1&&tmp[ls].tong[i]){pl=i;break;}
}
else {
tmp[ls].tong[i]=sz;sz=i;break;
}
}
//for(int i=1;i<=sz-1;++i)tmp[rs].tong[i]=0;
//for(int i=sz+1;i<=26;++i)tmp[ls].tong[i]=0;
tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
if(len(rs)==&&tmp[rs].tong[sz]==){pr=sz;}
register int zs=len(rs)-tmp[rs].tong[sz];
for(int i=sz+;i<=;++i){
tmp[rs].tong[i]=tmp[k].tong[i];
zs-=tmp[k].tong[i];
if(!zs)break;
// if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
}
}
else {
for(int i=;i>=;--i){
if(tmp[k].tong[i]<=sz)
{
tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
// if(len(ls)==1&&tmp[ls].tong[i]){pl=i;break;}
}
else {
tmp[ls].tong[i]=sz;sz=i;break;
}
}
//for(int i=26;i>=sz+1;--i)tmp[rs].tong[i]=0;
//for(int i=1;i<=sz-1;++i)tmp[ls].tong[i]=0;
tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
//if(len(rs)==1&&tmp[rs].tong[sz]==1){pr=sz;}
register int zs=len(rs)-tmp[rs].tong[sz];
for(int i=sz-;i>=;--i){
tmp[rs].tong[i]=tmp[k].tong[i];
zs-=tmp[k].tong[i];
if(!zs)break;
// if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
}
}
if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=;
else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=;
else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
tmp[k].lazy=;tmp[k].opt=;
} inline void merge(int u,int opt){
down(u);
for(register int i=;i<=;++i){
ans[i]+=tmp[u].tong[i];
}
if(len(u)>)tmp[u].lazy=;lg.push_back(u);
tmp[u].opt=opt;
} inline int zip(int k){
//cout<<"laidao!"<<endl;
for(int i=;i<=;++i)if(tmp[k].tong[i])return i;
} void find(int k,int l,int r){
if(l==r)return s[l]=zip(k),void();
down(k);
find(ls,l,mid);
find(rs,mid+,r);
} void query(int k,int l,int r,int L,int R,int opt){
if(L<=l&&r<=R)return merge(k,opt),void();
down(k);
if(L<=mid)query(ls,l,mid,L,R,opt);
if(R>mid)query(rs,mid+,r,L,R,opt);
} void ud(int k,int l,int r,int L,int R){
if(L<=l&&r<=R)return void();
if(L<=mid)ud(ls,l,mid,L,R);
if(R>mid)ud(rs,mid+,r,L,R);
update(k);
} void building(int k,int l,int r){
tmp[k].l=l;tmp[k].r=r;
if(l==r)return tmp[k].l=tmp[k].r=l,tmp[k].tong[s[l]]=,tmp[k].lazy=tmp[k].opt=,void();
building(ls,l,mid);building(rs,mid+,r);
update(k);
} bool cmp(int u,int v){return tmp[u].l<tmp[v].l;} void exch(int opt){
sort(lg.begin(),lg.end(),cmp);
for(int i=,sz,tt=,ts=;i<lg.size();++i){
sz=len(lg[i]);
memset(tmp[lg[i]].tong,,sizeof(tmp[lg[i]].tong));
if(opt){
for(;tt<=;++tt){
if(sz>=ans[tt]){
sz-=ans[tt];
tmp[lg[i]].tong[tt]=ans[tt];
}
else {
tmp[lg[i]].tong[tt]=sz;
ans[tt]-=sz;break;
}
}
}
else {
for(;ts>=;--ts){
if(sz>=ans[ts]){
sz-=ans[ts];
tmp[lg[i]].tong[ts]=ans[ts];
}
else {
tmp[lg[i]].tong[ts]=sz;
ans[ts]-=sz;break;
}
}
}
}
}
int main()
{
//freopen("da.in","r",stdin);
//freopen("te.out","w",stdout);
scanf("%d%d",&N,&M);
scanf("%s",S+);
for(int i=;i<=N;++i)s[i]=val(S[i]);
building(,,N);
for(int i=,l,r,opt;i<=M;++i){
scanf("%d%d%d",&l,&r,&opt);
memset(ans,,sizeof(ans));lg.clear();
query(,,N,l,r,opt);
exch(opt);
ud(,,N,l,r);
}
find(,,N);
char c;
for(int i=;i<=N;++i){
c=s[i]+'a'-;
printf("%c",c);
}
printf("\n");
//int ppx='P'-'a'+1;
//cout<<"ppx="<<ppx<<endl;
}

ac

string [线段树优化桶排]的更多相关文章

  1. Codeforces 558E A Simple Task (计数排序&&线段树优化)

    题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...

  2. Weak Pair---hud5877大连网选(线段树优化+dfs)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5877  题意:给你一颗树,有n个节点,每个节点都有一个权值v[i]:现在求有多少对(u,v ...

  3. CodeForces 558E(计数排序+线段树优化)

    题意:一个长度为n的字符串(只包含26个小字母)有q次操作 对于每次操作 给一个区间 和k k为1把该区间的字符不降序排序 k为0把该区间的字符不升序排序 求q次操作后所得字符串 思路: 该题数据规模 ...

  4. hdu 3698 UVA1490 Let the light guide us 线段树优化DP

    题目链接 and 题目大意 hdu3698 但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us 有一个\(n*m\)的平原,要求每行选一个点 ...

  5. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  6. D. Babaei and Birthday Cake---cf629D(最长上升子序列和+线段树优化)

    http://codeforces.com/problemset/problem/629/D 题目大意: 我第一反应就是求最长上升子序列和  但是数值太大了  不能直接dp求  可以用线段树优化一下 ...

  7. G. 神圣的 F2 连接着我们 线段树优化建图+最短路

    这个题目和之前写的一个线段树优化建图是一样的. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路 之前这个题目可以相当于一个模板,直接套用就可以了. 不 ...

  8. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  9. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路

    B - Legacy CodeForces - 787D 这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优 ...

随机推荐

  1. [转帖]2017年新闻: 中国CPU还在“群雄割据” ,印度已确定了国家指令集

    中国CPU还在“群雄割据” ,印度已确定了国家指令集 时间:2017-12-21 作者:观察者网 https://www.eet-china.com/news/201712210610.html   ...

  2. numpy中线性代数用法

    numpy中线性代数用法 矩阵乘法 >>> import numpy as np >>> x=np.array([[1,2,3],[4,5,6]]) >> ...

  3. Luogu P4095 [HEOI2013]Eden的新背包问题

    题目 求出从前往后的背包\(f_{i,j}\)和从后往前的背包\(F_{i,j}\). 那么对于询问\((d,e)\),答案就是\(\max\limits_{i=0}^e f_{d-1,i}+F_{d ...

  4. 如何输出opencv编译信息

    本文链接:https://mangoroom.cn/opencv/how-to-print-compile-info-of-opencv.html opencv提供了一个函数,利用这个函数可以输出当前 ...

  5. redis 命令都在这了

    DEL key [key ...]删除指定的key(一个或多个) DUMP key导出key的值 EXISTS key [key ...]查询一个key是否存在 EXPIRE key seconds设 ...

  6. vue城市选择组件

    适用于vue的城市选择组件 仓库地址 基本功能: 支持全选.反选以及全部清空. 支持按拼音筛选. 勾选省份将会勾选省份下所有城市. 返回数据可灵活处理. 安装 npm install cn-regio ...

  7. LeetCode 338. 比特位计数

    338. 比特位计数 题目描述 给定一个非负整数 num.对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回. 示例 示例 1: 输入: 2 输出 ...

  8. Eclipse 配置 tomcat

    1.第一步 去官网下载 进入点击 Downloads 点击如图位置下载 我下载的是 apache-tomcat-7.0.82.zip(图片中不是,但都是一样的) 我解压到D:\tomcat\apach ...

  9. Ubuntu:MySQL与phpmyadmin安装、配置并使用。

    0. 小建议 Ubuntu 16.04.因为MySQL对于Ubuntu 18.04不是很适配,会出现终端MySQL无法输入中文等问题.如果用Ubuntu 18.04,会需要多解决很多细节问题. 建议将 ...

  10. docker search - 搜寻镜像

    使用docker search 命令可以搜索docker hub官方仓库中的镜像. # docker search --help Usage: docker search [OPTIONS] TERM ...