题解 P5125 【不认识】
题目大意
有一个长度为
如何解密
谁不知道亦或的逆运算是或异啊
Subtask#1 20pts
使用二维数组,用
Subtask#2 30pts
观察到每个查询都是连续的区间,可以用 树套树 来维护这个问题。时间复杂度
也可以使用 分块套分块 解决,时间复杂度
观察到每个人认识的人在这个区间上都是 连续 的。对于一个人,我们只需记录这个人最左认识到的人的编号,和最右认识到的人的编号。注意到“认识”是有双向性的,所以我们可以只存储一个人向左最左认识到的人的编号,或另外一个。以最右认识到的人的编号为例,记为
时间复杂度
Subtask#3 50pts
观察到上一段中所提到的
考虑使用数据结构来维护这个
我们需要进行的更新是
-
求
\sum_{i=l}^r g(i) 的值; -
二分求出区间
[l,r] 上使g(i)<r 的最大的i ,记为k ; -
将区间
[i,k] 赋值为r 。
这样,我们就可以在
代码展示
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000010;
typedef long long ll;
ll n,q,lstans,idx,l,r,sum[maxn*4],rv[maxn*4],lzy[maxn*4];
void pushdown(ll o,ll l,ll r)
{
lzy[o<<1]=lzy[o<<1|1]=lzy[o];
rv[o<<1]=rv[o<<1|1]=lzy[o];
ll mid=(l+r)>>1;
sum[o<<1]=(mid-l+1)*lzy[o];
sum[o<<1|1]=(r-(mid+1)+1)*lzy[o];
lzy[o]=0;
}
void Set(ll o,ll l,ll r,ll sl,ll sr,ll v)
{
if(sl>r||sr<l)return;
if(sl<=l&&r<=sr){lzy[o]=v;sum[o]=(r-l+1)*v;rv[o]=v;return;}
ll mid=(l+r)>>1;
if(lzy[o])pushdown(o,l,r);
Set(o<<1,l,mid,sl,sr,v);
Set(o<<1|1,mid+1,r,sl,sr,v);
sum[o]=sum[o<<1]+sum[o<<1|1];
rv[o]=rv[o<<1|1];
}
ll Query(ll o,ll l,ll r,ll ql,ll qr)
{
if(ql>r||qr<l)return 0;
if(ql<=l&&r<=qr)return sum[o];
ll mid=(l+r)>>1;
if(lzy[o])pushdown(o,l,r);
return Query(o<<1,l,mid,ql,qr)+Query(o<<1|1,mid+1,r,ql,qr);
}
ll Find(ll o,ll l,ll r,ll v)
{
if(l==r)return l;
if(lzy[o])pushdown(o,l,r);
ll mid=(l+r)>>1;
if(rv[o<<1]>=v)return Find(o<<1,l,mid,v);
return Find(o<<1|1,mid+1,r,v);
}
int main()
{
scanf("%lld%lld",&n,&q);
for(ll i=1;i<=n;i++)Set(1,1,n,i,i,i);
while(q--)
{
scanf("%lld%lld",&l,&r);
l^=lstans;r^=lstans;
idx=Find(1,1,n,r);//the last number index witch <=r
idx--;
if(idx>=l)lstans=r*(idx-l+1)-Query(1,1,n,l,idx);
else lstans=0;
printf("%lld\n",lstans);
if(idx>=l)Set(1,1,n,l,idx,r);
}
return 0;
}
闲言碎语
如果不强制离线有什么好的做法?
出题人本人也想不到
为什么要弄Subtask呢?
因为本人的暴力(Subtask#2 的第三种解法)在随机数据下跑得比标程还快!
所以出题人设置了两组极限数据,专门卡时间复杂度为
如果有人用暴力过了此题,请联系出题人哦!