好几天之前做的题目了,一直想写一下博客也没腾出时间来,今天赶紧把坑给填上呼呼呼~

  这道题首先如果只考虑每个商店中没有时间限制的物品时,我们只需要使用一棵可持久化trie树来维护区间内的异或最大值即可,这样我们可以把两部分的问题分离开来。

  之后我们再考虑有时间限制与编号限制的情况下,该怎样做?无脑做法线段树套trie,直接在对应的区间trie树上贪心,如果该条边的最后更新时间在允许的范围内,说明可以走这条边。虽然这样也可以卡过去(主要在于卡空间),但我们来介绍一种更加妙妙的线段树分治做法。其实我感觉在这题的体现上就是离线版树套树?机房大佬貌似不认可,但我确实是这样觉得哒。

  我们考虑在线椴树上的一次区间查询,实际上是将查询的区间分成了log个已经处理好的小区间,分别查询之后再合并达到最终的答案。那么我们可以模拟这个在线段树上分裂区间的操作:

  1.如果当前处理的区间(l,r)完全包含于询问区间,我们将这个询问的区间在这一层进行处理。(这样的询问均不再下传,跳过后续步骤)

  2.如果询问的区间有涉及(l,mid)的范围,递归左区间处理。

  3.如果询问的区间有涉及(mid+1,r)的范围,递归右区间处理。

  (本题分治的区间表示时间的范围,可持久化trie负责处理编号的限制)。

  这样的复杂度是多少?我们可以分处理trie树与查询的两个方面来分析。处理trie树时,我们插入一个值是log的复杂度,而包含一个修改的总分治区间数也是log个,所以是\(O(nlog^{2}n)\)的复杂度。查询也是log的复杂度,一个查询最多被分别查询 log 次。所以复杂度依然是 \(O(nlog^{2}n)\) 的。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
int n, m, sz, qt, nt, tot, cnt, timer;
int ans[maxn], sum[maxn * ], id[maxn], q[maxn];
int bit[], ch[maxn * ][], num[maxn], root[maxn]; int read()
{
int x = , k = ;
char c; c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct ques
{
int l, r, s, t, x;
}Q[maxn]; struct modify
{
int id, val, t;
friend bool operator <(const modify& a, const modify& b)
{ return a.id < b.id; }
}P[maxn], ql[maxn], qr[maxn]; void Ins(int now, int last, int x, int val)
{
if(x < ) return;
bool t = (bit[x] & val);
ch[now][!t] = ch[last][!t]; ch[now][t] = ++ sz;
sum[ch[now][t]] = sum[ch[last][t]] + ;
Ins(ch[now][t], ch[last][t], x - , val);
} int Query(int l, int r, int x, int val)
{
if(l > r || x < ) return ;
int ans = ; bool t = val & bit[x];
if(sum[ch[r][!t]] - sum[ch[l][!t]])
ans = (bit[x] + Query(ch[l][!t], ch[r][!t], x - , val));
else ans = Query(ch[l][t], ch[r][t], x - , val);
return ans;
} int Check(int v)
{
int l = , r = nt, ret = ;
while(l <= r)
{
int mid = (l + r) >> ;
if(num[mid] <= v) ret = mid, l = mid + ;
else r = mid - ;
}
return ret;
} void Work(int l, int r)
{
sz = , nt = ;
for(int i = l; i <= r; i ++)
{
nt ++; root[nt] = ++ sz;
Ins(root[nt], root[nt - ], , P[i].val);
num[nt] = P[i].id;
}
for(int i = ; i <= qt; i ++)
{
int l = Check(Q[q[i]].l - ), r = Check(Q[q[i]].r);
ans[q[i]] = max(ans[q[i]], Query(root[l], root[r], , Q[q[i]].x));
}
} void Divide(int l, int r, int L, int R, int pres)
{
if(l > r || !pres) return;
int mid = (L + R) >> ; qt = ;
for(int i = ; i <= pres; i ++)
if(Q[id[i]].s <= L && R <= Q[id[i]].t) q[++ qt] = id[i];
Work(l, r); if(L == R) return;
int ll = , rr = ;
for(int i = l; i <= r; i ++)
{
if(P[i].t <= mid) ql[++ ll] = P[i];
else qr[++ rr] = P[i];
}
for(int i = ; i <= ll; i ++) P[i + l - ] = ql[i];
for(int i = ; i <= rr; i ++) P[i + l + ll - ] = qr[i]; int ind = ;
for(int i = ; i <= pres; i ++)
{
if(Q[id[i]].s <= L && R <= Q[id[i]].t) continue;
if(Q[id[i]].s <= mid) swap(id[i], id[++ ind]);
}
Divide(l, l + ll - , L, mid, ind);
ind = ;
for(int i = ; i <= pres; i ++)
{
if(Q[id[i]].s <= L && R <= Q[id[i]].t) continue;
if(Q[id[i]].t > mid) swap(id[i], id[++ ind]);
}
Divide(l + ll, r, mid + , R, ind);
} int main()
{
bit[] = ; for(int i = ; i <= ; i ++) bit[i] = bit[i - ] << ;
n = read(), m = read();
for(int i = ; i <= n; i ++) root[i] = ++ sz, Ins(root[i], root[i - ], , read());
for(int i = ; i <= m; i ++)
{
int opt = read();
if(!opt)
{
++ timer; P[++ tot].id = read();
P[tot].val = read(); P[tot].t = timer;
}
else
{
Q[++ cnt].l = read(); Q[cnt].r = read();
Q[cnt].x = read(); int d = read();
Q[cnt].s = max(timer - d, ) + ; Q[cnt].t = timer;
ans[cnt] = Query(root[Q[cnt].l - ], root[Q[cnt].r], , Q[cnt].x);
}
}
sort(P + , P + + tot);
for(int i = ; i <= cnt; i ++) id[i] = i;
Divide(, tot, , timer, cnt);
for(int i = ; i <= cnt; i ++) printf("%d\n", ans[i]);
return ;
}

【题解】FJOI2015火星商店问题的更多相关文章

  1. 【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)

    [题解]P4585 [FJOI2015]火星商店问题(线段树套Trie树) 语文没学好不要写省选题面!!!! 题目大意: 有\(n\)个集合,每个集合有个任意时刻都可用的初始元素.现在有\(m\)个操 ...

  2. 【LG4585】[FJOI2015]火星商店问题

    [LG4585][FJOI2015]火星商店问题 题面 bzoj权限题 洛谷 \(Notice:\) 关于题面的几个比较坑的地方: "一天"不是一个操作,而是有0操作就相当于一天开 ...

  3. [FJOI2015]火星商店问题

    [FJOI2015]火星商店问题 神仙线段树分治...不过我不会. 这题用线段树套可持久化Trie还是能写的. 常数有点大,洛谷垫底水平. // luogu-judger-enable-o2 #inc ...

  4. 洛谷 P4585 [FJOI2015]火星商店问题 解题报告

    P4585 [FJOI2015]火星商店问题 题目描述 火星上的一条商业街里按照商店的编号\(1,2,\dots,n\) ,依次排列着\(n\)个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非 ...

  5. [FJOI2015]火星商店问题(线段树分治,可持久化,Trie树)

    [FJOI2015]火星商店问题 前天考了到线段树分治模板题,全场都切了,就我不会QAQ 于是切题无数的Tyher巨巨就告诉我:"你可以去看看火星商店问题,看了你就会了." 第一道 ...

  6. [FJOI2015]火星商店问题(分治+可持久化)

    题目描述 火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价.每个商店每天都有可能进一些新商品,其标价可能与已 ...

  7. BZOJ4137 & 洛谷4585:[FJOI2015]火星商店问题

    https://www.lydsy.com/JudgeOnline/problem.php?id=4137 https://www.luogu.org/problemnew/show/P4585 火星 ...

  8. 【bzoj4137】[FJOI2015]火星商店问题

    *题目描述: 火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价.每个商店每天都有可能进一些新商品,其标价可能 ...

  9. 【洛谷】P4585 [FJOI2015]火星商店问题

    题解 题目太丧,OJ太没有良心,我永远喜欢LOJ! (TLE报成RE,垃圾洛谷,我永远喜欢LOJ) 好的,平复一下我debug了一上午崩溃的心态= =,写一写这道题的题解 把所有限制去掉,给出一个值, ...

随机推荐

  1. Redis系列五 Redis持久化

    Redis持久化 一.RDB(Redis DataBase) 1.介绍 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里. Red ...

  2. dota2交换物品

    改成.bat 因为文件就可以 echo/>>c:/windows/system32/drivers/etc/hostsecho 111.230.82.224 steamcommunity. ...

  3. python3 BeautifulSoup模块使用

    BeautifulSoup就是Python的一个HTML或XML的解析库,可以用它来方便地从网页中提取数据.官方解释如下: Beautiful Soup提供一些简单的.Python式的函数来处理导航. ...

  4. QT 标题栏隐藏可拖拽

    这个也是我网上找到了 为了方便,记录一下 void mousePressEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void ...

  5. Appium的一点一滴:Android KEYCODE键值

    转自:http://blog.csdn.net/crisschan/article/details/50419963 - 电话键 键名 描述 键值 KEYCODE_CALL 拨号键 5 KEYCODE ...

  6. Linux中常用Shell命令

    本随笔文章,由个人博客(鸟不拉屎)转移至博客园 写于:2018 年 05 月 04 日 原地址:https://niaobulashi.com/archives/linux-shell.html -- ...

  7. 了解Python控制流语句——while 语句

    while 语句 Python 中 while 语句能够让你在条件为真的前提下重复执行某块语句. while 语句是 循环(Looping) 语句的一种.while 语句同样可以拥有 else 子句作 ...

  8. CodeForces - 776C(前缀和+思维)

    链接:CodeForces - 776C 题意:给出数组 a[n] ,问有多少个区间和等于 k^x(x >= 0). 题解:求前缀和,标记每个和的个数.对每一个数都遍历到1e5,记录到答案. # ...

  9. JavaScript写的一个带AI的井字棋

    最近有一门课结束了,需要做一个井字棋的游戏,我用JavaScript写了一个.首先界面应该问题不大,用html稍微写一下就可以.主要是人机对弈时的ai算法,如何使电脑方聪明起来,是值得思考一下的.开始 ...

  10. (原创)白话KMP算法详解

    引子:BF暴力算法 KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ...