string [线段树优化桶排]
题意大概是给你一个字符串,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 [线段树优化桶排]的更多相关文章
- Codeforces 558E A Simple Task (计数排序&&线段树优化)
题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...
- Weak Pair---hud5877大连网选(线段树优化+dfs)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 题意:给你一颗树,有n个节点,每个节点都有一个权值v[i]:现在求有多少对(u,v ...
- CodeForces 558E(计数排序+线段树优化)
题意:一个长度为n的字符串(只包含26个小字母)有q次操作 对于每次操作 给一个区间 和k k为1把该区间的字符不降序排序 k为0把该区间的字符不升序排序 求q次操作后所得字符串 思路: 该题数据规模 ...
- hdu 3698 UVA1490 Let the light guide us 线段树优化DP
题目链接 and 题目大意 hdu3698 但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us 有一个\(n*m\)的平原,要求每行选一个点 ...
- 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 ...
- D. Babaei and Birthday Cake---cf629D(最长上升子序列和+线段树优化)
http://codeforces.com/problemset/problem/629/D 题目大意: 我第一反应就是求最长上升子序列和 但是数值太大了 不能直接dp求 可以用线段树优化一下 ...
- G. 神圣的 F2 连接着我们 线段树优化建图+最短路
这个题目和之前写的一个线段树优化建图是一样的. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路 之前这个题目可以相当于一个模板,直接套用就可以了. 不 ...
- D - The Bakery CodeForces - 834D 线段树优化dp···
D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...
- B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路
B - Legacy CodeForces - 787D 这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优 ...
随机推荐
- djangourl进阶
- spring boot-4.配置文件
官方文档的23.4章节介绍了关于配置文件的内容 springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的 ...
- mysql 官网下载太慢了,来这里!!!
RT.去官网下载mysql简直是折磨,太慢了!!! 但我还是坚持住了,下载下来了,我自己下载的是 MAC 5.7.27版本,网盘分享下,有需要的自提吧: 链接:https://pan.baidu.co ...
- [ZJOI2007]时态同步 题解
题面 这道题是一道比较水的XXOI题: 我们可以发现,反着思考题目就变为了让所有叶子节点同时发出信号,然后这些信号同时到达根节点: 可以证明,这样答案不会改变: 那么我们可以自下而上dfs(),设f[ ...
- mysql5.6
5.6 与之后版本有差别本文以5.6为例** 1.mysql5.6安装 本文采用2进制安装 mkdir /server/tools -p cd /server/tools 1.下载 wget http ...
- Git 设置 用户名 和 邮箱
git config --global user.name "Vincent" git config --global user.email "********@qq.c ...
- [Linux]Linux下经常会用到的简单实例(持续更新)
1.查找某些进程并结束他们: ps -elf | grep '进程关键字' | awk '{print $4}'| xargs kill -9 解析: ps -elf 的 -e 代表列出所有进程,-l ...
- Qt设置生成的exe文件图标
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_37354286/article/d ...
- 牛客练习赛47 A DongDong破密码 (异或性质,递推)
链接:https://ac.nowcoder.com/acm/contest/904/A 来源:牛客网 DongDong破密码 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 1310 ...
- php晚了8小时 PHP5中的时间相差8小时的解决办法
php页面顶部加一句date_default_timezone_set("Asia/Shanghai");或者直接在php.ini设置date.timezone=Asia/Shan ...