【訓練小結】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);
	}
}

極限數據效率對比
在這裏插入圖片描述
詢問很多,但是同樣有修改的隨機數據
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章