题目大意:给定一个序列,多次求区间内逆序对个数 强制在线
让我们呐喊一声:出题人卡常数丧心病狂!
再来一次:出题人卡常数丧心病狂!!!!
不强制在线的直接莫队就能搞 强制在线我是跪了QTZ
首先看这数据范围肯定O(n√nlogn)了
我们分块 令cnt[i][j]为从第i块的开头起到第j个点这段区间的逆序对数
这个用树状数组就可以O(n√nlogn)搞出来 我一开始直接用可持久化线段树搞这部分 常数大TLE到死啊
然后对于每次查询,如果左右端点在同一块直接树状数组暴力,如果左右端点在不同一块的话 令temp为x所在块的下一块的左端点
对于[temp,y]部分的逆序对已经预处理出来了,直接调用即可
对于[x,temp-1]部分的逆序对,我们对于[x,temp-1]的每一个a[i]求出[i+1,y]区间内有多少比a[i]小的数,这个用可持久化线段树搞(总感觉不用 是我的错觉?)
然后就搞出来了……这TLE叫一个爽 上一个写法跑了整整30s我也是醉了 明明不强制在线还有40s的时限改成强制在线居然尼玛只剩15s了……
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;
struct abcd{
abcd *ls,*rs;
int num;
void* operator new (size_t size,abcd *_,abcd *__,int ___);
}*tree[M],mempool[1001001],*C=mempool;
int n,m,tot,block,ans;
int a[M],l[M],r[M],belong[M];
int cnt[250][M];
pair<int,int>b[M];
int c[M],tim[M],T;
void Update(int x)
{
for(;x;x-=x&-x)
{
if(tim[x]!=T)
tim[x]=T,c[x]=0;
c[x]++;
}
}
int Get_Ans(int x)
{
int re=0;
for(;x<=tot;x+=x&-x)
if(tim[x]==T)
re+=c[x];
return re;
}
void* abcd :: operator new (size_t size,abcd *_,abcd *__,int ___)
{
C->ls=_;
C->rs=__;
C->num=___;
return C++;
}
abcd* Build_Tree(abcd *p,int x,int y,int val)
{
int mid=x+y>>1;
if(x==y) return new (0x0,0x0,p->num+1)abcd;
if(val<=mid) return new (Build_Tree(p->ls,x,mid,val),p->rs,p->num+1)abcd;
else return new (p->ls,Build_Tree(p->rs,mid+1,y,val),p->num+1)abcd;
}
int Get_Ans(abcd *p1,abcd *p2,int x,int y,int l,int r)
{
int mid=x+y>>1;
if(p1->num==p2->num)
return 0;
if(x==l&&y==r)
return p2->num-p1->num;
if(r<=mid) return Get_Ans(p1->ls,p2->ls,x,mid,l,r);
if(l>mid) return Get_Ans(p1->rs,p2->rs,mid+1,y,l,r);
return Get_Ans(p1->ls,p2->ls,x,mid,l,mid) + Get_Ans(p1->rs,p2->rs,mid+1,y,mid+1,r);
}
inline int Query(int x,int y)
{
int i,re=0;
if(belong[x]==belong[y])
{
++T;
for(i=x;i<=y;i++)
re+=Get_Ans(a[i]+1),Update(a[i]);
return re;
}
re+=cnt[belong[x]+1][y];
for(i=x;i<l[belong[x]+1];i++)
re+=Get_Ans(tree[i],tree[y],0,tot+1,0,a[i]-1);
return re;
}
int main()
{
//freopen("3744.in","r",stdin);
//freopen("3744.out","w",stdout);
int i,j,k,x,y;
cin>>n;
for(i=1;i<=n;i++)
scanf("%d",&b[i].first),b[i].second=i;
sort(b+1,b+n+1);
for(i=1;i<=n;i++)
{
if(i==1||b[i].first!=b[i-1].first)
++tot;
a[b[i].second]=tot;
}
tree[0]=new (0x0,0x0,0)abcd;
tree[0]->ls=tree[0]->rs=tree[0];
for(i=1;i<=n;i++)
tree[i]=Build_Tree(tree[i-1],0,tot+1,a[i]);
block=static_cast<int>(sqrt(n)+1e-7);
for(i=1;i<=n;i++)
belong[i]=(i-1)/block+1;
for(i=1;(i-1)*block+1<=n;i++)
l[i]=(i-1)*block+1,r[i]=min(i*block,n);
for(i=1;(i-1)*block+1<=n;i++)
{
++T;
for(j=(i-1)*block+1;j<=n;j++)
{
cnt[i][j]=cnt[i][j-1]+Get_Ans(a[j]+1);
Update(a[j]);
}
}
cin>>m;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);x^=ans;y^=ans;
printf("%d\n", ans=Query(x,y) );
}
}