【训练小结】Petrozavodsk Summer 2015 - Yandex Cup Stage 2

trac

题解

I

简单圆方树
我的另一篇博客

D

题意:维护一个序列,支持两种操作:区间修改成一个数;询问区间内出现次数大于区间长度一半的数(没有输出-1)。N,Q≤105

题解:
from jiangshibiao:
先思考答案数字的性质。若把查询区间划成一个一个段。这个数一定在一个区间中出现次数>区间长度的一半。
所以,我们采用线段树维护这个序列。区间修改就正常地lazy标记,up时顺便维护子树里出现次数最多的数以及其出现次数。(如果出现次数小于区间长度,则直接不记录)。用数学归纳法可以证明答案如果存在,一定可以合并到。
现在问题来了:在up的时候,我们需要知道左右两个子区间的“候选数字”Lp和Rp分别在当前区间内出现的次数。
数颜色是很困难的一件事,我们只能对每一种颜色开一个数据结构维护。为了实现方便,我采用了动态开点的线段树>_<。也就是说,对于每一段颜色(l,r,v),我们会在rtv的线段树里的(l,r)区间加1。这样up时就可以花log的时间求答案了。
再考虑修改对这些线段树的影响。这是个经典模型,我们可以在全局维护一棵平衡树,表示每一段连续的颜色(set即可)。区间修改时,可以暴力提取那些被包含的小区间,在它们各自颜色的rt里删掉它们的贡献,再补入一个新的大区间。
由于每一种颜色的线段树也要down,内存消耗巨大;而区间在+1后可能会被撤销。所以我们可以每次对=0的节点回收内存,收效很不错。

我的做法:(很遗憾被卡了)
直接随机,每次有>1/2的概率选到。那么我们随机24次就可以在200000次询问做到错误概率在0.5%。
同样需要用回收空间的线段树技巧来查询出现次数。
这种做法在答案不全是-1的时候比正解更快
然而出题人卡了这种做法。有极限数据,时限5s,本机4s,但是还是过不了、QwQ

总结:
学到了一个技巧:
区间覆盖+区间出现次数查询可以用动态开点的线段树分颜色维护+set维护颜色段数。因为有颜色段数可以暴力维护的优美性质。
另外,动态开点+回收空间十分巧妙。这样空间是nlogn的,因为任何时刻颜色出现总次数是n
如果是区间加大概就只能分块了。训练的时候只想到分块+随机、这种做法极限数据本机都要16s,不可能过。
关于分块技巧,还要多练习,很不熟练!
注意linux 和 windows的rand_max不同,对拍一直WA是这个原因

附上两份代码和效率对比

//正解
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const ld inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 400020;
const ll mod = 1e9 + 7;

struct node{
	int l,r,tp,x;
}dt[maxn];
int n,m,q;
int b[maxn],tot,a[maxn];
set <pr> s;

namespace Seg{
#define ls(x) ls[x]
#define rs(x) rs[x]
	const int M = 5e6 + 20;
	int ls[M],rs[M],sum[M],add[M],rt[maxn];
	int Void[M],tops;
	
	inline void Add(int &x,int d,int l,int r){
		if ( !x ) x = Void[tops--];
		sum[x] += d * (r - l + 1) , add[x] += d;
	}
	inline void pushdown(int x,int l,int mid,int r){
		if ( add[x] ){
			Add(ls(x),add[x],l,mid);
			Add(rs(x),add[x],mid + 1,r);
			add[x] = 0;
		}
	}
	inline void update(int x){
		sum[x] = sum[ls(x)] + sum[rs(x)];
	}
	void modify(int &x,int l,int r,int L,int R,int d){
		if ( !x ) x = Void[tops--];
		if ( L <= l && R >= r ) { Add(x,d,l,r); return; }
		int mid = (l + r) >> 1;
		pushdown(x,l,mid,r);
		if ( L <= mid ) modify(ls(x),l,mid,L,R,d);
		if ( R > mid ) modify(rs(x),mid + 1,r,L,R,d);
		update(x);
	}
	void clear(int x){
		ls[x] = rs[x] = sum[x] = add[x] = 0;
	}
	void dfs(int x,int l,int r){
		if ( !x ) return;
		if ( l == r ){
			Void[++tops] = x;
			clear(x);
			return;
		}
		int mid = (l + r) >> 1;
		dfs(ls(x),l,mid);
		dfs(rs(x),mid + 1,r);
		clear(x);
		Void[++tops] = x;
	}
	void modify_c(int &x,int l,int r,int L,int R){
		if ( L > R || !x ) return;
		if ( L <= l && R >= r ){
			dfs(x,l,r);
			x = 0;
			return;
		}
		int mid = (l + r) >> 1;
		pushdown(x,l,mid,r);
		if ( L <= mid ) modify_c(ls(x),l,mid,L,R);
		if ( R > mid ) modify_c(rs(x),mid + 1,r,L,R);
		update(x);
		if ( !sum[x] ){
			clear(x);
			Void[++tops] = x;
			x = 0;
		}
	}
	int query(int x,int l,int r,int L,int R){
		if ( L > R || !x ) return 0;
		if ( L <= l && R >= r ) return sum[x];
		int mid = (l + r) >> 1; int res = 0;
		pushdown(x,l,mid,r);
		if ( L <= mid ) res = query(ls(x),l,mid,L,R);
		if ( R > mid ) res += query(rs(x),mid + 1,r,L,R);
		return res;
	}
	#undef ls
	#undef rs
}
using namespace Seg;

namespace Seg2{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
	const int M = 2e6 + 20;
	int id[M],cov[M];
	
	inline void cover(int x,int d){
		cov[x] = id[x] = d;
	}
	inline void pushdown(int x){
		if ( cov[x] ){
			cover(ls(x),cov[x]);
			cover(rs(x),cov[x]);
			cov[x] = 0;
		}
	}
	inline void update(int x,int l,int r){
		int c1 = id[ls(x)] , c2 = id[rs(x)];
		if ( !c1 ) id[x] = c2;
		else if ( !c2 ) id[x] = c1;
		else if ( c1 == c2 ) id[x] = c1;
		else{
			int d1 = Seg::query(rt[c1],1,n,l,r) , d2 = Seg::query(rt[c2],1,n,l,r);
			if ( d1 > (r - l + 1) / 2 ) id[x] = c1;
			else if ( d2 > (r - l + 1) / 2 ) id[x] = c2;
			else id[x] = 0;
		} 
	}
	void build(int x,int l,int r){
		if ( l == r ){
			id[x] = a[l];
			return;
		}
		int mid = (l + r) >> 1;
		build(ls(x),l,mid);
		build(rs(x),mid + 1,r);
		update(x,l,r);
	}
	void modify(int x,int l,int r,int L,int R,int d){
		if ( L <= l && R >= r ) { cover(x,d); return; }
		int mid = (l + r) >> 1;
		pushdown(x);
		if ( L <= mid ) modify(ls(x),l,mid,L,R,d);
		if ( R > mid ) modify(rs(x),mid + 1,r,L,R,d);
		update(x,l,r);
	}
	int query(int x,int l,int r,int L,int R){
		if ( L <= l && R >= r ){
			int d = Seg::query(rt[id[x]],1,n,L,R);
			if ( d > (R - L + 1) / 2 ) return id[x];
		 	return 0;
		}
		int mid = (l + r) >> 1; int res1 = 0 , res2 = 0;
		pushdown(x);
		if ( L <= mid ) res1 = query(ls(x),l,mid,L,R);
		if ( res1 ) return res1;
		if ( R > mid ) res2 = query(rs(x),mid + 1,r,L,R);
		if ( res2 ) return res2;
		//int d1 = Seg::query(rt[res1],1,n,L,R) , d2 = Seg::query(rt[res2],1,n,L,R);
		//if ( d1 > (R - L + 1) / 2 ) return res1;
		//else if ( d2 > (R - L + 1) / 2 ) return res2;
		return 0;
	}
	#undef ls
	#undef rs
}


void pre(){
	sort(b + 1,b + tot + 1);
	tot = unique(b + 1,b + tot + 1) - b - 1;
	for (int i = 1 ; i <= n ; i++) a[i] = lower_bound(b + 1,b + tot + 1,a[i]) - b;
	for (int i = 1 ; i <= q ; i++) dt[i].x = lower_bound(b + 1,b + tot + 1,dt[i].x) - b;
}
void modify(int l,int r,int x){
	while ( 1 ){
		auto it = s.lower_bound(mp(r,inf));
		if ( it == s.begin() ) break;	
		auto it2 = it;
		--it;
		if ( it2 == s.end() || (*it2).fi > r + 1 ) s.insert(mp(r + 1,(*it).se));
		if ( (*it).fi < l ){
			modify_c(rt[(*it).se],1,n,l,r);
			break;
		}
		modify_c(rt[(*it).se],1,n,l,r);
		s.erase(it);
	}
	s.insert(mp(l,x));
	modify(rt[x],1,n,l,r,1);
	Seg2::modify(1,1,n,l,r,x);
}
inline int getnum(int id){
	auto it = s.lower_bound(mp(id,inf));
	--it;
	return (*it).se;
}
int query(int l,int r){
	int x = Seg2::query(1,1,n,l,r);
	//int c = query(rt[x],1,n,l,r);
	if ( x ) return b[x];
	return -1;
}
void build(){
	repd(i,M - 1,1) Void[++tops] = i;
//	cerr<<M<<endl;
	int last = 1;
	rep(i,2,n + 1){
		if ( a[i] != a[i - 1] ){
			modify(rt[a[last]],1,n,last,i - 1,1);
			s.insert(mp(last,a[last]));
			last = i;
		}
	}
	Seg2::build(1,1,n);
}
int main(){
	//freopen("input.txt","r",stdin);
	//freopen("2.out","w",stdout);

	srand(20000907);
	scanf("%d",&n);
	for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]) , b[++tot] = a[i];
	scanf("%d",&q);
	for (int i = 1 ; i <= q ; i++){
		char ch[20]; int l,r,x;
		scanf("%s",ch);
		if ( ch[0] == 'q' ){
			scanf("%d %d",&l,&r);
			dt[i] = (node){l,r,1,0};
		}
		else{
			scanf("%d %d %d",&l,&r,&x);
			dt[i] = (node){l,r,2,x};
			b[++tot] = x;
		}
	}
	pre();
	build();
	for (int i = 1 ; i <= q ; i++){
		if ( dt[i].tp == 1 ){
			printf("%d\n",query(dt[i].l,dt[i].r));
		}
		else modify(dt[i].l,dt[i].r,dt[i].x);
	}
}
//随机化
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const ld inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 400020;
const ll mod = 1e9 + 7;

namespace Seg{
#define ls(x) ls[x]
#define rs(x) rs[x]
	const int M = 5e6 + 20;
	int ls[M],rs[M],sum[M],add[M],rt[maxn];
	int Void[M],tops;
	
	inline void Add(int &x,int d,int l,int r){
		if ( !x ) x = Void[tops--];
		sum[x] += d * (r - l + 1) , add[x] += d;
	}
	inline void pushdown(int x,int l,int mid,int r){
		if ( add[x] ){
			Add(ls(x),add[x],l,mid);
			Add(rs(x),add[x],mid + 1,r);
			add[x] = 0;
		}
	}
	inline void update(int x){
		sum[x] = sum[ls(x)] + sum[rs(x)];
	}
	void modify(int &x,int l,int r,int L,int R,int d){
		if ( !x ) x = Void[tops--];
		if ( L <= l && R >= r ) { Add(x,d,l,r); return; }
		int mid = (l + r) >> 1;
		pushdown(x,l,mid,r);
		if ( L <= mid ) modify(ls(x),l,mid,L,R,d);
		if ( R > mid ) modify(rs(x),mid + 1,r,L,R,d);
		update(x);
	}
	void clear(int x){
		ls[x] = rs[x] = sum[x] = add[x] = 0;
	}
	void dfs(int x,int l,int r){
		if ( !x ) return;
		if ( l == r ){
			Void[++tops] = x;
			clear(x);
			return;
		}
		int mid = (l + r) >> 1;
		dfs(ls(x),l,mid);
		dfs(rs(x),mid + 1,r);
		clear(x);
		Void[++tops] = x;
	}
	void modify_c(int &x,int l,int r,int L,int R){
		if ( L > R || !x ) return;
		if ( L <= l && R >= r ){
			dfs(x,l,r);
			x = 0;
			return;
		}
		int mid = (l + r) >> 1;
		pushdown(x,l,mid,r);
		if ( L <= mid ) modify_c(ls(x),l,mid,L,R);
		if ( R > mid ) modify_c(rs(x),mid + 1,r,L,R);
		update(x);
		if ( !sum[x] ){
			clear(x);
			Void[++tops] = x;
			x = 0;
		}
	}
	int query(int x,int l,int r,int L,int R){
		if ( L > R || !x ) return 0;
		if ( L <= l && R >= r ) return sum[x];
		int mid = (l + r) >> 1; int res = 0;
		pushdown(x,l,mid,r);
		if ( L <= mid ) res = query(ls(x),l,mid,L,R);
		if ( R > mid ) res += query(rs(x),mid + 1,r,L,R);
		return res;
	}
}
using namespace Seg;


struct node{
	int l,r,tp,x;
}dt[maxn];
int n,m,q;
int b[maxn],tot,a[maxn],flag;
set <pr> s;

void pre(){
	sort(b + 1,b + tot + 1);
	tot = unique(b + 1,b + tot + 1) - b - 1;
	for (int i = 1 ; i <= n ; i++) a[i] = lower_bound(b + 1,b + tot + 1,a[i]) - b;
	for (int i = 1 ; i <= q ; i++) dt[i].x = lower_bound(b + 1,b + tot + 1,dt[i].x) - b;
}
void modify(int l,int r,int x){
	flag++;
	while ( 1 ){
		auto it = s.lower_bound(mp(r,inf));
		if ( it == s.begin() ) break;	
		auto it2 = it;
		--it;
		if ( it2 == s.end() || (*it2).fi > r + 1 ) s.insert(mp(r + 1,(*it).se));
		if ( (*it).fi < l ){
			modify_c(rt[(*it).se],1,n,l,r);
			break;
		}
		modify_c(rt[(*it).se],1,n,l,r);
		s.erase(it);
	}
	s.insert(mp(l,x));
	modify(rt[x],1,n,l,r,1);
}
inline int getnum(int id){
	auto it = s.lower_bound(mp(id,inf));
	--it;
	return (*it).se;
}
int query(int l,int r){

	for (int i = 1 ; i <= 30 ; i++){
		int x = (ll)rand() * rand() % (r - l + 1) + l;
		int d = getnum(x);
		if ( query(rt[d],1,n,l,r) > (r - l + 1)/ 2 ) return b[d];
	}
	return -1;
}
void build(){
	repd(i,M - 1,1) Void[++tops] = i;
	int last = 1;
	rep(i,2,n + 1){
		if ( a[i] != a[i - 1] ){
			modify(rt[a[last]],1,n,last,i - 1,1);
			s.insert(mp(last,a[last]));
			last = i;
		}
	}
}
int main(){
	//freopen("input.txt","r",stdin);
	//freopen("1.out","w",stdout);

	srand(20000907);
	scanf("%d",&n);
	for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]) , b[++tot] = a[i];
	scanf("%d",&q);
	for (int i = 1 ; i <= q ; i++){
		char ch[20]; int l,r,x;
		scanf("%s",ch);
		if ( ch[0] == 'q' ){
			scanf("%d %d",&l,&r);
			dt[i] = (node){l,r,1,0};
		}
		else{
			scanf("%d %d %d",&l,&r,&x);
			dt[i] = (node){l,r,2,x};
			b[++tot] = x;
		}
	}
	pre();
	build();
	for (int i = 1 ; i <= q ; i++){
		if ( dt[i].tp == 1 ){
			printf("%d\n",query(dt[i].l,dt[i].r));
		}
		else modify(dt[i].l,dt[i].r,dt[i].x);
	}
}

极限数据效率对比
在这里插入图片描述
询问很多,但是同样有修改的随机数据
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值