http://codeforces.com/problemset/problem/538/F
一开始能想到的只有暴力查询 打了个表发现即使n达到2e5时 需要查询的次数也只是2e6左右 所以找每个节点在k叉时对应的子节点区间有多少节点比当前节点要小 主席树维护一下即可
但是想想 其实还可以用线段树离线处理 先把查询拿出来按所查询的权值排序 然后对于每个查询 把所有小于该查询值的序列元素都更新到线段树里 单点更新区间查询
主席树在线
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
int l;
int r;
int val;
};
node tree[8000010];
int ary[200010],tmp[200010],root[200010],ans[200010];
int n,len,num;
ll getmin(ll a,ll b)
{
if(a<b) return a;
else return b;
}
int build(int l,int r)
{
int cur,m;
cur=num++;
tree[cur].l=0,tree[cur].r=0,tree[cur].val=0;
if(l==r) return cur;
m=(l+r)/2;
tree[cur].l=build(l,m);
tree[cur].r=build(m+1,r);
return cur;
}
int update(int rot,int tar,int val,int l,int r)
{
int cur,m;
cur=num++;
tree[cur]=tree[rot];
tree[cur].val+=val;
if(l==r) return cur;
m=(l+r)/2;
if(tar<=m) tree[cur].l=update(tree[rot].l,tar,val,l,m);
else tree[cur].r=update(tree[rot].r,tar,val,m+1,r);
return cur;
}
int query(int lrot,int rrot,int pl,int pr,int l,int r)
{
int res,m;
if(pl<=l&&r<=pr) return tree[rrot].val-tree[lrot].val;
res=0,m=(l+r)/2;
if(pl<=m) res+=query(tree[lrot].l,tree[rrot].l,pl,pr,l,m);
if(pr>m) res+=query(tree[lrot].r,tree[rrot].r,pl,pr,m+1,r);
return res;
}
int main()
{
ll k,i,tn;
int p;
scanf("%d",&n);
tn=n;
for(i=1;i<=n;i++)
{
scanf("%d",&ary[i]);
tmp[i]=ary[i];
}
sort(tmp+1,tmp+n+1);
len=unique(tmp+1,tmp+n+1)-tmp-1;
num=0;
root[0]=build(1,len);
for(i=1;i<=n;i++)
{
p=lower_bound(tmp+1,tmp+len+1,ary[i])-tmp;
root[i]=update(root[i-1],p,1,1,len);
}
ans[1]=0;
for(i=1;i+1<=n;i++)
{
if(ary[i]>ary[i+1]) ans[1]++;
}
for(k=2;k<=n-1;k++)
{
ans[k]=0;
for(i=1;k*(i-1)+2<=tn;i++)
{
p=lower_bound(tmp+1,tmp+len+1,ary[i])-tmp-1;
if(p>=1) ans[k]+=query(root[k*(i-1)+1],root[getmin(k*i+1,tn)],1,p,1,len);
}
}
for(i=1;i<=n-1;i++)
{
printf("%d",ans[i]);
if(i<n-1) printf(" ");
else printf("\n");
}
return 0;
}
/*
10
10 9 8 7 6 5 4 3 2 1
*/
线段树离线
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node0
{
int id;
int val;
};
struct node1
{
int id;
int l;
int r;
int val;
};
struct node2
{
int l;
int r;
int val;
};
node0 ary[200010];
node1 order[3000010];
node2 tree[8000010];
int ans[3000010];
int n,tot;
ll getmin(ll a,ll b)
{
if(a<b) return a;
else return b;
}
bool cmpI(node0 n1,node0 n2)
{
return n1.val<n2.val;
}
bool cmpII(node1 n1,node1 n2)
{
return n1.val<n2.val;
}
void pushup(int cur)
{
tree[cur].val=tree[2*cur].val+tree[2*cur+1].val;
}
void build(int l,int r,int cur)
{
int m;
tree[cur].l=l;
tree[cur].r=r;
tree[cur].val=0;
if(l==r) return;
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
}
void update(int tar,int val,int cur)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].val+=val;
return;
}
if(tar<=tree[2*cur].r) update(tar,val,2*cur);
else update(tar,val,2*cur+1);
pushup(cur);
}
int query(int pl,int pr,int cur)
{
int res;
if(pl<=tree[cur].l&&tree[cur].r<=pr) return tree[cur].val;
res=0;
if(pl<=tree[2*cur].r) res+=query(pl,pr,2*cur);
if(pr>=tree[2*cur+1].l) res+=query(pl,pr,2*cur+1);
return res;
}
int main()
{
ll k,i,j,tn;
scanf("%d",&n);
tn=n;
for(i=1;i<=n;i++)
{
ary[i].id=i;
scanf("%d",&ary[i].val);
}
tot=0;
for(k=1;k<=n-1;k++)
{
for(i=1;k*(i-1)+2<=tn;i++)
{
tot++;
order[tot].id=k,order[tot].l=k*(i-1)+2,order[tot].r=getmin(k*i+1,tn),order[tot].val=ary[i].val;
}
}
sort(ary+1,ary+n+1,cmpI);
sort(order+1,order+tot+1,cmpII);
build(1,n,1);
j=1;
for(i=1;i<=tot;i++)
{
while(ary[j].val<order[i].val)
{
update(ary[j].id,1,1);
j++;
}
ans[order[i].id]+=query(order[i].l,order[i].r,1);
}
for(i=1;i<=n-1;i++)
{
printf("%d",ans[i]);
if(i<n) printf(" ");
else printf("\n");
}
return 0;
}