完了,壹佰场了……我估计我连壹万分都没有……$\text{QwQ}$
考场上全是暴力。
鬼知道分是哪里来的。
没挂分就是了。
|
22
|
Miemeng | 55
00:00:51
|
60
00:00:45
|
40
00:00:40
|
155
00:00:51
|
还应该再努力些……
一棵神奇的线段树。
虽然暴力加剪枝可过,但是正解跑飞快。
首先观察神奇的操作,发现就是把一个点所控制子序列中所有的逆序对删掉。
那么每个点作为子序列中的点只能被删一次。
于是用线段树加速这个删的过程,保证了复杂度$\Theta(N \log N + q \log N)$。
有点像小清新
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define N 222222
#define LL long long
#define lc(k) (k<<1)
#define rc(k) (k<<1|1)
using namespace std;
int pn,qn;
int arr[N];
LL dp[N],ans=0;
vector<LL>ansv;
namespace szsz{
int maxr=200010;
LL pre[N];
inline int lowbit(int x){
return x&(-x);
}
void add(int pos,int v){
while(pos<=maxr){
pre[pos]+=v;
pos+=lowbit(pos);
}
}
LL query(int pos){
LL res=0;
while(pos){
res+=pre[pos];
pos-=lowbit(pos);
}
return res;
}
}
struct XDS{
int l,r;
int val;
LL dat;
}rt[N<<2];
void build(int k,int l,int r){
rt[k].l=l,rt[k].r=r;
if(l==r){
rt[k].dat=dp[l];
rt[k].val=arr[l];
return ;
}
int mid=(l+r)/2;
build(lc(k),l ,mid);
build(rc(k),mid+1,r );
rt[k].val=min(rt[lc(k)].val,rt[rc(k)].val);
}
LL spchange(int k,int l,int r,int va){
// cout<<k<<" "<<rt[k].l<<" "<<rt[k].r<<" "<<va<<" "<<rt[k].val<<endl;
LL anss=0;
if(rt[k].val>va)
return 0;
if(rt[k].l==rt[k].r){
LL va=rt[k].dat;
rt[k].val=0x7fffffff;
return va;
}
int mid=(rt[k].l+rt[k].r)/2;
if(mid >= l)
anss+=spchange(lc(k),l,r,va);
if(mid < r)
anss+=spchange(rc(k),l,r,va);
rt[k].val=min(rt[lc(k)].val,rt[rc(k)].val);
return anss;
}
int main(){
#ifndef LOCAL
freopen("count.in" ,"r",stdin);
freopen("count.out","w",stdout);
#endif
int a;
ios_base::sync_with_stdio(false);
cin>>pn>>qn;
for(int i=1;i<=pn;i++)
cin>>arr[i];
for(int i=pn;i>=1;i--){
dp[i]=szsz::query(arr[i]-1);
ans+=dp[i];
szsz::add(arr[i],1);
}
ansv.push_back(ans);
build(1,1,pn);
for(int i=1;i<=qn;i++){
// cout<<"-------------"<<endl;
cin>>a;
ans-=spchange(1,a,pn,arr[a]);
// cout<<"-------------"<<endl;
ansv.push_back(ans);
}
for(int i=0;i<ansv.size();i++){
cout<<ansv[i]<<" ";
}
cout<<endl;
}
原文:https://www.cnblogs.com/kalginamiemeng/p/11796201.html