在太陽西斜的這個世界裏,置身天上之森。
等這場戰爭結束後,不歸之人與望眼欲穿的人們,人人本着正義之名。
長存不滅的過去,逐漸消逝的未來。
我 回 來 了,
縱使日薄西山,即便看不到未來,
此時此刻的光輝,盼君勿忘。
——世上最幸福的女孩
題面說的很繞,第個操作,說了一堆期望什麼的,最後發現要乘上,所以就是求情況之和嘛
我們考慮褻瀆什麼時候可以被觸發
首先他一定會觸發一次,那麼這個時候需要讓場上所有人的血量,想要觸發下一次,一定需要有一個人的血量在的範圍內,如果觸發第二次呢?不難發現就是需要有一個人的血量在的範圍內,以此類推
所以對於傷害值爲的情況,褻瀆能夠被觸發的次數就是最大的,使得
因爲每次只有插入一個數,所以我們發現一定會逐漸變大
考慮變化的量,應該是左右,算出來大概是,可以證明這個東西,也就是說最多隻會變化次
那麼我們可以形成一個基本的思路就是每次插入一個數的時候,快速的找到需要更改的位置,然後暴力更改,後面那個東西可以利用一個樹狀數組進行維護
考慮快速插入的時候怎麼找到需要更改的位置
我們發現,當傷害值爲,當前次數爲的時候,我們只有插入的一個在裏面的數的時候,才能夠向後擴展,所以我們可以儲存下來每一個現在的目標區間,就是,然後插入的時候找到所有包含的區間暴力更新,更新之後插入新的目標區間
因爲最多隻會被查找次,我們嘗試每次用的時間查找一個滿足條件的區間,那麼這個時候複雜度是,是基本可以接受的
那麼問題就轉化成了每次求包含一個點的每一個滿足條件的區間
我們可以使用線段樹+set的方法來解決
我們建立個set,儲存的是所有左端點爲的區間的右端點的值
再建立一棵線段樹,每個節點儲存左端點位於子區間中的區間的右端點的最大值,線段樹的每個葉子節點就相應的對應每一個set
對於一個,每次我們不停地查找線段樹上的這一段區間,每次查詢出來的就是一個滿足條件的,直到這一段區間的最大右端點,就一定沒有滿足條件的區間了,停止查詢
怕被卡常,所以這裏我選擇了手寫平衡樹
但是這樣的寫法還有一些細節
比如說我們每次真的只會往後擴展一次嗎?
比如說先插入了一個,對於來說,不能更新
接下來插入一個,這個時候不是隻更新一次,因爲殺掉之後還可以殺掉,這個時候會更新兩次
因爲我們只儲存了每個當前的目標區間,還可能後面有但是當時不能更新的,所以我們需要再開一個樹狀數組來儲存小兵的情況,每次拓展多次
這一段的代碼:
if(opt==1){
bit2.add(x,1);//x位置多了一個人
while(1){
node now=seg.query(1,1,n,1,x);//查找當前l在[1,x]中r最大的區間
if(now.max<x)break;//如果比x小,就沒有了,結束循環
treap.del(now.maxid,now.max),seg.update(1,1,n,now.maxid);//在平衡樹中刪去這一條線段,同時線段樹的信息需要更新
int bel=now.max-now.maxid+1,l=now.maxid,r=now.max;//r-l+1就是這個點的d,嘗試向右拓展
while(bit2.ask(r)-bit2.ask(l-1)>0&&l<=n)//如果這個區間有小兵
l+=bel,r+=bel,bit1.add(bel,1);//更新答案
if(l<=n)treap.ins(l,r),seg.update(1,1,n,l);//如果還在[1,n]裏面就插入新的目標線段
}
}
另外樹狀數組的代碼也需要相應修改,因爲我們可能查找到一段的,這個同樣是合法的,但是查詢的時候可能會出錯,因爲,所以樹狀數組查詢時,如果,即可
空間複雜度寫回收的話,時間複雜度大約
要寫兩棵樹狀數組+一棵線段樹+一棵平衡樹,我選擇了結構體封裝的版本,同時表達信仰啊qwq
chtholly->維護答案的樹狀數組
almeria->維護小兵的樹狀數組
ithea->維護區間的平衡樹
nephren->線段樹
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int son[N*10][2],siz[N*10],val[N*10],treap[N*10];
int bin[N*10],binsiz;
int root[N],tot;
struct node{
int maxid,max;
}seg[N<<2];
struct chtholly_almeria{
int bit[N];
int lowbit(int o){
return o&-o;
}
void add(int o,int x){
for(;o<=n;o+=lowbit(o))bit[o]+=x;
}
int ask(int o){
if(o>n)o=n;
int res=0;
for(;o;o-=lowbit(o))res+=bit[o];
return res;
}
}Chtholly,Almeria;
struct ithea{
int newnode(){
if(!binsiz)return ++tot;
else return bin[binsiz--];
}
void delnode(int x){
bin[++binsiz]=x;
siz[x]=val[x]=treap[x]=son[x][0]=son[x][1]=0;
}
void update(int x){
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
int merge(int u,int v){
if(!u||!v)return u|v;
int rt;
if(treap[u]<treap[v])son[rt=u][1]=merge(son[u][1],v);
else son[rt=v][0]=merge(u,son[v][0]);
return update(rt),rt;
}
void split(int o,int &u,int &v,int k){
if(!o){u=v=0;return;}
if(val[o]<=k)split(son[u=o][1],son[o][1],v,k);
else split(son[v=o][0],u,son[o][0],k);
update(o);
}
void ins(int l,int r){
int lft,rht;
split(root[l],lft,rht,r);
int u=newnode();
treap[u]=rand(),siz[u]=1,val[u]=r;
root[l]=merge(merge(lft,u),rht);
}
void del(int l,int r){
int lft,mid,rht;
split(root[l],lft,rht,r);
split(lft,lft,mid,r-1);
root[l]=merge(lft,rht);
delnode(mid);
}
int max(int l){
int u=root[l];
while(son[u][1])u=son[u][1];
return val[u];
}
}Ithea;
struct nephren{
# define lc (u<<1)
# define rc (u<<1|1)
node merge(node l,node r){
if(l.max>r.max)return l;
else return r;
}
void update(int u,int l,int r,int x){
if(l==r){
if(root[l])seg[u].max=Ithea.max(l),seg[u].maxid=l;
else seg[u].max=seg[u].maxid=0;
return;
}
int mid=l+r>>1;
if(x<=mid)update(lc,l,mid,x);
else update(rc,mid+1,r,x);
seg[u]=merge(seg[lc],seg[rc]);
}
node query(int u,int l,int r,int ql,int qr){
if(l>=ql&&r<=qr)return seg[u];
int mid=l+r>>1;
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
return merge(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
}
}Nephren;
int main()
{
// freopen("testdata.in","r",stdin);
srand(19260817);
read(n),read(m);
Rep(i,1,n){
Chtholly.add(i,1);
Ithea.ins(1,i),Nephren.update(1,1,n,1);
}
Rep(i,1,m){
int opt,x,y;
read(opt),read(x);
if(opt==1){
Almeria.add(x,1);
while(1){
node now=Nephren.query(1,1,n,1,x);
if(now.max<x)break;
Ithea.del(now.maxid,now.max),Nephren.update(1,1,n,now.maxid);
int bel=now.max-now.maxid+1,l=now.maxid,r=now.max;
while(Almeria.ask(r)-Almeria.ask(l-1)>0&&l<=n)
l+=bel,r+=bel,Chtholly.add(bel,1);
if(l<=n)Ithea.ins(l,r),Nephren.update(1,1,n,l);
}
}
else read(y),printf("%d\n",Chtholly.ask(y)-Chtholly.ask(x-1));
}
return 0;
}