trac
简单圆方树
我的另一篇博客
题意:维护一个序列,支持两种操作:区间修改成一个数;询问区间内出现次数大于区间长度一半的数(没有输出-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
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<
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
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);
}
}