zoukankan      html  css  js  c++  java
  • CF558E-A Simple Task

    题目

    开始给出一个长度为(n)的小写字母串,(m)次操作,每次选一个区间,把这个区间进行升序或降序排序。最后输出所有操作结束后的串。

    (nle 10^5,mle 5 imes 10^4)

    分析

    神思路!!

    其实主要是要注意到这个字母表为26非常小,所以可以考虑使用基数排序!事实上排序也可以看成统计每种数有多少个按顺序输出的过程。

    二十六颗线段树,维护区间中每种字母的出现次数。排序的时候遍历所有的字母,把该排在前面的全部移到前面。这可以用一个支持区间求和,区间加法,区间清零的线段树来做,写的时候标记可以用一个二元组来表示,(x=a_0*x+a_1*len)

    总而言之用每个字母的位置来刻画这个序列。

    其实很多字符串问题都是基于字母表比较小来做的。

    代码

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<utility>
    #include<algorithm>
    using namespace std;
    int read() {
    	int x=0,f=1;
    	char c=getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int maxn=1e5+1;
    const int maxc=26;
    int n,m;
    char s[maxn];
    pair<int,int> operator + (pair<int,int> a,pair<int,int> b) {
    	return make_pair(a.first*b.first,a.second*b.first+b.second);
    }
    struct SGT {
    	int t[maxn<<2];
    	pair<int,int> tag[maxn<<2];
    	void build(int x,int l,int r) {
    		if (l==r) return;
    		t[x]=0,tag[x]=make_pair(1,0);
    		int mid=(l+r)>>1;
    		build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    	}
    	void doit(int x,int l,int r,pair<int,int> d) {
    		t[x]=t[x]*d.first+(r-l+1)*d.second;
    		tag[x]=tag[x]+d;
    	}
    	void pushdown(int x,int l,int mid,int r) {
    		doit(x<<1,l,mid,tag[x]);
    		doit(x<<1|1,mid+1,r,tag[x]);
    		tag[x]=make_pair(1,0);
    	}
    	void modify(int x,int L,int R,int l,int r,pair<int,int> d) {
    		if (L==l && R==r) {
    			doit(x,L,R,d);
    			return;
    		}
    		int mid=(L+R)>>1;
    		pushdown(x,L,mid,R);
    		if (r<=mid) modify(x<<1,L,mid,l,r,d); else 
    		if (l>mid) modify(x<<1|1,mid+1,R,l,r,d); else
    		modify(x<<1,L,mid,l,mid,d),modify(x<<1|1,mid+1,R,mid+1,r,d);
    		t[x]=t[x<<1]+t[x<<1|1];
    	}
    	void clear(int l,int r) {
    		if (l>r) return;
    		modify(1,1,n,l,r,make_pair(0,0));
    	}
    	void inc(int l,int r) {
    		if (l>r) return;
    		modify(1,1,n,l,r,make_pair(1,1));
    	}
    	int query(int x,int L,int R,int l,int r) {
    		if (L==l && R==r) return t[x];
    		int mid=(L+R)>>1;
    		pushdown(x,L,mid,R);
    		if (r<=mid) return query(x<<1,L,mid,l,r);
    		if (l>mid) return query(x<<1|1,mid+1,R,l,r);
    		return query(x<<1,L,mid,l,mid)+query(x<<1|1,mid+1,R,mid+1,r);
    	}
    	int query(int l,int r) {
    		if (l>r) return 0;
    		return query(1,1,n,l,r);
    	}
    } sgt[maxc];
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	n=read(),m=read();
    	scanf("%s",s+1);
    	for (int i=0;i<maxc;++i) sgt[i].build(1,1,n);
    	for (int i=1;i<=n;++i) sgt[s[i]-'a'].inc(i,i);
    	while (m--) {
    		int l=read(),r=read(),o=read();
    		if (o) {
    			int alr=0;
    			for (int i=0;i<maxc;++i) {
    				int tmp=sgt[i].query(l,r);
    				sgt[i].clear(l,r);
    				sgt[i].inc(l+alr,l+alr+tmp-1);
    				alr+=tmp;
    			}
    		} else {
    			int alr=0;
    			for (int i=maxc-1;i>=0;--i) {
    				int tmp=sgt[i].query(l,r);
    				sgt[i].clear(l,r);
    				sgt[i].inc(l+alr,l+alr+tmp-1);
    				alr+=tmp;
    			}
    		}
    	}
    	for (int i=1,j;i<=n;++i) {
    		for (j=0;j<maxc;++j) if (sgt[j].query(i,i)) {
    			putchar('a'+j);
    			break;
    		}
    	}
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    努力的一分不会少
    C语言中的数组的访问方式
    代码的规划与规范化
    Manjaro中源码安装gcc7.1
    周围都是敌人,方法总比问题多
    elementary os 0.4.1下编译GCC-7.1源码并安装成功
    C语言中的基础知识变量探讨
    19年的桌面KDE的风雨和陪伴,没有什么能够割舍
    《手把手教你学C语言》学习笔记(10)--- 程序的循环控制
    copy 的实现原理与深浅拷贝
  • 原文地址:https://www.cnblogs.com/owenyu/p/7155598.html
Copyright © 2011-2022 走看看