[BZOJ3295] [Cqoi2011]动态逆序对

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3295

题目大意

给定1~n的序列,每次删去一个数,询问每次删之前的逆序对数

题解

我们把它转化成CDQ模型
删除,我们可以倒过来看成添加
对于每个数我们给他一个时间戳,本身的权值和它在序列中的位置
这样就转化成了一个三维点对间的问题
我们再看逆序对
每个点时间戳在它后面的分为两种情况
1.序列中位置在它后面,权值比它小
2.序列中位置在它前面,权值比它大
分开处理即可
注意ans要用longlong

const
    maxn=100005;
type
    data=record
    x,y,z:longint;
    end;
var
    pp,temp,ask:array[0..maxn]of data;
    tt,bit,que:array[0..maxn]of longint;
    ans:array[0..maxn]of int64;
    i,j,k:longint;
    n,m,len,kind:longint;
procedure sort(l,r:longint);
var i,j,a,b,c:longint; d:data;
begin
    i:=l; j:=r; a:=ask[(l+r)div 2].x; b:=ask[(l+r)div 2].y; c:=ask[(l+r)div 2].z;
    repeat
        while (ask[i].x<a)or((ask[i].x=a)and(ask[i].y<b)and(kind=1))or((ask[i].x=a)and(ask[i].z<c)and(kind=2)) do inc(i);
        while (ask[j].x>a)or((ask[j].x=a)and(ask[j].y>b)and(kind=1))or((ask[j].x=a)and(ask[j].z>c)and(kind=2)) do dec(j);
        if not(i>j) then
        begin
            d:=ask[i]; ask[i]:=ask[j]; ask[j]:=d;
            inc(i); dec(j);
        end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r);
end;

procedure update(pos,val:longint);
begin
    while pos<=n do
        begin
            inc(bit[pos],val);
            inc(pos,pos and (-pos));
        end;
end;

function query(pos:longint):longint;
var sum:longint;
begin
    sum:=0;
    while pos>0 do
        begin
            inc(sum,bit[pos]);
            dec(pos,pos and (-pos));
        end;
    exit(sum);
end;

procedure cdq1(l,r:longint);
var mid,i,j,k:longint;
begin
    if l=r then exit;
    mid:=(l+r)>>1;
    cdq1(l,mid); cdq1(mid+1,r);
    i:=l; j:=mid+1; len:=l-1;
    while (i<=mid)and(j<=r) do
        if ask[i].y<ask[j].y
        then begin inc(len); temp[len]:=ask[i]; update(ask[i].z,1); inc(i); end
        else begin inc(len); temp[len]:=ask[j]; inc(ans[ask[j].x],query(n)-query(ask[j].z)); inc(j); end;
    while i<=mid do
        begin inc(len); temp[len]:=ask[i]; update(ask[i].z,1); inc(i); end;
    while j<=r do
        begin inc(len); temp[len]:=ask[j]; inc(ans[ask[j].x],query(n)-query(ask[j].z)); inc(j); end;
    for i:=l to mid do
        update(ask[i].z,-1);
    for i:=l to r do
        ask[i]:=temp[i];
end;

procedure cdq2(l,r:longint);
var mid,i,j,k:longint;
begin
    if l=r then exit;
    mid:=(l+r)>>1;
    cdq2(l,mid); cdq2(mid+1,r);
    i:=l; j:=mid+1; len:=l-1;
    while (i<=mid)and(j<=r) do
        if ask[i].z<ask[j].z
        then begin inc(len); temp[len]:=ask[i]; update(ask[i].y,1); inc(i); end
        else begin inc(len); temp[len]:=ask[j]; inc(ans[ask[j].x],query(n)-query(ask[j].y)); inc(j); end;
    while i<=mid do
        begin inc(len); temp[len]:=ask[i]; update(ask[i].y,1); inc(i); end;
    while j<=r do
        begin inc(len); temp[len]:=ask[j]; inc(ans[ask[j].x],query(n)-query(ask[j].y)); inc(j); end;
    for i:=l to mid do
        update(ask[i].y,-1);
    for i:=l to r do
        ask[i]:=temp[i];
end;

begin
    readln(n,m);
    for i:=1 to n do
        begin
            readln(que[i]);
            tt[que[i]]:=i;
        end;
    len:=0;
    for i:=m+1 downto 2 do
        begin
            inc(len);
            readln(ask[len].z);
            ask[len].x:=i;
            ask[len].y:=tt[ask[len].z];
            que[ask[len].y]:=-1;
        end;
    for i:=1 to n do
        begin
            if que[i]=-1 then continue;
            inc(len);
            ask[len].x:=1;
            ask[len].y:=i;
            ask[len].z:=que[i];
        end;
    fillchar(bit,sizeof(bit),0);
    fillchar(ans,sizeof(ans),0);
    kind:=1; sort(1,n);
    for i:=1 to n do
        pp[i]:=ask[i];
    cdq1(1,n);
    for i:=1 to n do ask[i]:=pp[i];
    cdq2(1,n);
    for i:=2 to m+1 do
        ans[i]:=ans[i-1]+ans[i];
    for i:=m+1 downto 2 do
        writeln(ans[i]);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值