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 这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优 ...
随机推荐
- Win10无法安装.net framework 3.5出错提示无法安装以下功能该怎么办?
在Windows操作系统中,.NET Framewor对今天应用程序的成功提供了的安全解决方案,它能强化两个安全模型间的平衡.在提供对资源的访问,以便以完成有用的工作,对应用程序的安全性作细致的控制以 ...
- 第九周课程总结&实验报告
实验任务详情: 完成火车站售票程序的模拟. 要求: (1)总票数1000张: (2)10个窗口同时开始卖票: (3)卖票过程延时1秒钟: (4)不能出现一票多卖或卖出负数号票的情况. public c ...
- HDU 2100 Lovekey (26进制大数、字符串)
Lovekey Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- 【转帖】Linux系统上面qemu 模拟arm
零基础在Linux系统搭建Qemu模拟arm https://blog.csdn.net/weixin_42489042/article/details/81145038 自己没搞定 改天再试试 感谢 ...
- springBoot2.0 Yaml值获取
1. pom.xml添加如下依赖 <dependency> <groupId>org.springframework.boot</groupId> <arti ...
- hashlib模块和hmac模块
hashlib模块和hmac模块 hashlib模块 一.导入方式 import hashlib 二.作用 无论你丢什么字符串,他都会返回一串 固定长度的字符串 三.模块功能 3.1 经常使用 imp ...
- const关键字 C与C++分析
1 C与C++的区别 1.1.C允许定义两个变量名相同的变量,而C++不允许. 在C语言中是允许定义两个名字相同的全局变量. 在C++中是不允许定义两个名字相同的全局变量. 测试代码: /* 编译环 ...
- IDEA一些有用的功能
使用 Type Info 如果你想要更多的关于符号的信息,例如从哪里或它的类型是什么, 快速文档可以很好的帮到您,您可以按下 Ctrl+Q 来调用它,然后你会看到一个包含这些细节的弹出窗口.如果您不需 ...
- Java学习:identityHashCode和hashCode方法
System类提供了一个identityHashCode(Object x)方法,这个方法返回的是指定对象的精确hashCode值,也就是根据该对象的地址计算得到的hashCode值. 当某个类的ha ...
- wex5 如何使用蓝牙 ble
使用蓝牙插件 需要在js中添加 require("cordova!cordova-plugin-ble-central"); ble插件具体文档: http://docs.we ...