題解
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);
}
}
極限數據效率對比
詢問很多,但是同樣有修改的隨機數據