题解 string

Posted 欢迎,Administrator-09

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 string相关的知识,希望对你有一定的参考价值。

传送门

前40分很好拿,考场上打了个区间覆盖优化,期望骗到50~70pts,
结果写了半天的区间覆盖优化还是只有40分。。。

正解和[HEOI2016/TJOI2016]排序很像然而我并没有做过这道题
以下思路来源于土神:
首先暴力的时间复杂度是\\(O(m*nlogn)\\)
显然m次操作并不能卡掉 区间覆盖优化:???
那么尝试处理那个n
这是个范围\\(1e5\\)的序列问题,优化成\\(O(mlogn)\\)就差不多能过了
要求单次修改logn,那么考虑线段树
如果只是一个字母,我们可以用线段树维护该字母的有无
现在有26个字母,该如何处理呢?
开26棵线段树! 这tm居然真是正解这都什么乱七八糟的
每棵线段树维护一个区间上该字母的个数
每处理一次请求用桶统计请求区间内每个字母的个数,
然后upd修改 实际上为了方便我在每次query时将这段区间清空了

p.s. 我调了半天不对,最后发现fread把我的scanf("%s", s+1)卡掉了
p.s. 这题要是再想卡时间的话也许可以试试在线段树基础上再套个区间覆盖优化

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 150010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c==\'-\') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
char s[N];

struct segment{
	char key;
	struct node{int l, r, cnt, tag, len;}tree[N<<2];
	#define t(p) tree[p]
	#define cnt(p) tree[p].cnt
	#define tag(p) tree[p].tag
	#define len(p) tree[p].len
	inline void pushup(int p) {cnt(p)=cnt(p<<1)+cnt(p<<1|1);}
	inline void pushdown(int p) {
		if (tag(p)==-1) return ;
		//cout<<"tag "<<tag(p)<<endl;
		cnt(p<<1)=len(p<<1)*tag(p); tag(p<<1)=tag(p);
		cnt(p<<1|1)=len(p<<1|1)*tag(p); tag(p<<1|1)=tag(p);
		tag(p)=-1;
	}
	void build(int p, int l, int r) {
		//cout<<"build "<<p<<\' \'<<l<<\' \'<<r<<endl;
		t(p).l=l; t(p).r=r; len(p)=r-l+1; tag(p)=-1;
		if (l>=r) {cnt(p)=(s[l]==key); return ;}
		int mid = (l+r)>>1;
		if (l<=mid) build(p<<1, l, mid);
		if (r>mid) build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void query(int p, int l, int r, int* a) {
		if (!cnt(p)) return ;
		//cout<<"query "<<p<<\' \'<<l<<\' \'<<r<<\' \'<<t(p).l<<\' \'<<t(p).r<<\' \'<<cnt(p)<<\' \'<<tag(p)<<endl;
		if (t(p).l>=l && t(p).r<=r) {a[key-\'a\'+1]+=cnt(p); cnt(p)=0; tag(p)=0; return ;}
		pushdown(p);
		int mid=(t(p).l+t(p).r)>>1, ans=0;
		if (l<=mid) query(p<<1, l, r, a);
		if (r>mid) query(p<<1|1, l, r, a);
		pushup(p);
	}
	void upd(int p, int l, int r) {
		//cout<<"upd "<<p<<\' \'<<l<<\' \'<<r<<\' \'<<t(p).l<<\' \'<<t(p).r<<endl;
		if (l<=t(p).l && r>=t(p).r) {cnt(p)=len(p); tag(p)=1; return ;}
		pushdown(p);
		int mid=(t(p).l+t(p).r)>>1;
		if (l<=mid) upd(p<<1, l, r);
		if (r>mid) upd(p<<1|1, l, r);
		pushup(p);
	}
	void put(int p, int l, int r) {
		if (!cnt(p)) return ;
		pushdown(p);
		if (l>=r) {s[l]=key; return;}
		int mid=(l+r)>>1;
		if (l<=mid) put(p<<1, l, mid);
		if (r>mid) put(p<<1|1, mid+1, r);
	}
}seg[26];

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	int a[27], sum[27];
	
	n=read(); m=read();
	scanf("%s", s+1);
	//cout<<s<<endl;
	for (int i=0; i<26; ++i) seg[i].key=\'a\'+i; //, cout<<seg[i].key<<endl;
	for (int i=0; i<26; ++i) seg[i].build(1, 1, n);
	for (int i=1,l,r,k; i<=m; ++i) {
		l=read(); r=read(); k=read();
		memset(a, 0, sizeof(a)); sum[0]=0;
		for (int i=1; i<=26; ++i) seg[i-1].query(1, l, r, a);
		//for (int i=1; i<=n; ++i) cout<<a[i]<<\' \'; cout<<endl;
		for (int i=1; i<=26; ++i) sum[i]=sum[i-1]+a[i];
		if (k&1) {
			for (int i=1; i<=26; ++i) if (a[i]) seg[i-1].upd(1, l+sum[i-1], l+sum[i]-1); //, cout<<"change"<<i<<\' \'<<l+sum[i-1]<<\' \'<<l+sum[i]-1<<endl;
		}
		else {
			//for (int i=1; i<=n; ++i) cout<<sum[i]<<\' \'; cout<<endl;
			for (int i=1; i<=26; ++i) if (a[i]) seg[i-1].upd(1, r-sum[i]+1, r-sum[i-1]);
		}
	}
	for (int i=0; i<26; ++i) seg[i].put(1, 1, n);
	//for (int i=1; i<=n; ++i) cout<<int(s[i]); cout<<endl;
	printf("%s\\n", s+1);

	return 0;
}

以上是关于题解 string的主要内容,如果未能解决你的问题,请参考以下文章

如何理解这段代码片段中的两对括号?

Failed to convert property value of type ‘java.lang.String‘ to required type ‘int‘ for property(代码片段

Java 求解划分字母区间

面试常用的代码片段

golang代码片段(摘抄)

21个常用代码片段