我在做最后一道题的时候,这道题因为本身是非常难的吗
ZROI#3300. 舔狗的上位
很神人的题啊。。
出题人关于这道题正解是怎么想出来的的解释:
题意是一个长度为
一开始有个
然后这个做法因为你要对每个
所以考虑对于所有
然后神人做法来了,我们有一个看似很没用的性质,就是
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
#define ll long long
struct node{
int ls,rs,sum;
void clear(){
ls=rs=sum=0;
}
}tree[MAXN*30];
int rt[MAXN],n,d,t;
int a[MAXN],st[MAXN*30];
int top,cnt,b[MAXN];
int New(){return top?st[top--]:++cnt;}
void del(int x){
tree[x].clear();
st[++top]=x;
}
void pushup(int u){
int ls=tree[u].ls,rs=tree[u].rs;
tree[u].sum=tree[ls].sum+tree[rs].sum;
}
int merge(int u,int v,int l,int r){
if(!u||!v)return u+v;
if(l==r){
tree[u].sum+=tree[v].sum;
del(v);
return u;
}
int mid=(l+r)/2;
tree[u].ls=merge(tree[u].ls,tree[v].ls,l,mid);
tree[u].rs=merge(tree[u].rs,tree[v].rs,mid+1,r);
pushup(u),del(v);
return u;
}
void split(int &u,int &v,int l,int r,int L,int R){
if(L>r||R<l||!u)return;
if(L<=l&&r<=R){
v=u,u=0;
return;
}
if(!v)v=New();
int mid=(l+r)/2;
split(tree[u].ls,tree[v].ls,l,mid,L,R);
split(tree[u].rs,tree[v].rs,mid+1,r,L,R);
pushup(u),pushup(v);
}
void update(int &u,int l,int r,int x,int y){
if(!u)u=New();
if(l==r){
tree[u].sum+=y;
return;
}
int mid=(l+r)/2;
if(x<=mid)update(tree[u].ls,l,mid,x,y);
else update(tree[u].rs,mid+1,r,x,y);
pushup(u);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n>>d;
for(int i=1;i<=n;i++)
cin>>a[i],b[i]=a[i];
sort(b+1,b+1+n);
int m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+m,a[i])-b;
for(int i=1;i<=n;i++)
update(rt[0],1,m,i,b[i]-b[i-1]);
ll ans=0;
for(int i=1;i<=n;i++){
split(rt[0],rt[i],1,m,1,a[i]);
ans+=tree[rt[i]].sum;
if(i>=d)
rt[0]=merge(rt[0],rt[i-d+1],1,m);
}
cout<<ans<<"\n";
for(int i=0;i<=n;i++)
rt[i]=0;
for(int i=1;i<=cnt;i++)
tree[i].clear();
cnt=top=0;
}
return 0;
}