码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ2141]排队

时间:2018-01-20 13:59:59      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:show   uniq   markdown   main   大小   个数   unique   逆序   线段树   

BZOJ
Luogu
题意:每次交换序列中的两个数,然后求逆序对数

sol

看一眼这不是动态逆序对嘛。
所以就是一个裸的树套树呀
树状数组套线段树
修改的时候需要讨论一波交换的两个数的大小关系,设交换的两个位置是\(a,b\)\(a<b\)
1、\(h_a=h_b\)

...

2、\(h_a<h_b\)

首先交换后\(a,b\)会贡献一对逆序对所以ans++
对于位置在\(a\)前面或者\(b\)后面的数都没有影响
对于处于\(a,b\)之间的数\(i\)
\(h_i=h_a\)\(h_i=h_b\),那么交换后会产生1的贡献
\(h_a<h_i<h_b\),那么交换后会产生2的贡献

3、\(h_a>h_b\)

交换后\(a,b\)会少一对逆序对所以ans--
同理,对于位置在\(a\)前面或者\(b\)后面的数都没有影响
对于处于\(a,b\)之间的数\(i\)
\(h_i=h_a\)\(h_i=h_b\),那么交换后会减少1的贡献
\(h_a<h_i<h_b\),那么交换后会减少2的贡献

讨论一波以后就是树套树的板子了

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 20005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}

struct segment_tree{int ls,rs,num;}t[N*100];
int n,m,h[N],o[N],len,rt[N],tot;
long long ans;
void modify(int &x,int l,int r,int p,int v)
{
    if (!x) x=++tot;t[x].num+=v;
    if (l==r) return;
    int mid=l+r>>1;
    if (p<=mid) modify(t[x].ls,l,mid,p,v);
    else modify(t[x].rs,mid+1,r,p,v);
}
int query(int x,int l,int r,int ql,int qr)
{
    if (!x||ql>qr) return 0;
    if (l>=ql&&r<=qr) return t[x].num;
    int mid=l+r>>1,s=0;
    if (ql<=mid) s+=query(t[x].ls,l,mid,ql,qr);
    if (qr>mid) s+=query(t[x].rs,mid+1,r,ql,qr);
    return s;
}
int main()
{
    n=gi();
    for (int i=1;i<=n;i++) o[i]=h[i]=gi();
    sort(o+1,o+n+1);len=unique(o+1,o+n+1)-o-1;
    for (int i=1;i<=n;i++) h[i]=lower_bound(o+1,o+len+1,h[i])-o;
    for (int i=1;i<=n;i++)
        for (int j=i;j<=n;j+=j&-j)
            modify(rt[j],1,len,h[i],1);
    for (int i=1;i<=n;i++)
        for (int j=i-1;j;j-=j&-j)
            ans+=query(rt[j],1,len,h[i]+1,len);
    printf("%lld\n",ans);
    m=gi();
    while (m--)
    {
        int a=gi(),b=gi();
        if (a>b) swap(a,b);
        if (h[a]<h[b])
        {
            ++ans;
            for (int j=b-1;j;j-=j&-j) ans+=query(rt[j],1,len,h[a],h[b])+query(rt[j],1,len,h[a]+1,h[b]-1);
            for (int j=a;j;j-=j&-j) ans-=query(rt[j],1,len,h[a],h[b])+query(rt[j],1,len,h[a]+1,h[b]-1);
        }
        if (h[a]>h[b])
        {
            --ans;
            for (int j=b-1;j;j-=j&-j) ans-=query(rt[j],1,len,h[b],h[a])+query(rt[j],1,len,h[b]+1,h[a]-1);
            for (int j=a;j;j-=j&-j) ans+=query(rt[j],1,len,h[b],h[a])+query(rt[j],1,len,h[b]+1,h[a]-1);
        }
        for (int j=a;j<=n;j+=j&-j) modify(rt[j],1,len,h[a],-1),modify(rt[j],1,len,h[b],1);
        for (int j=b;j<=n;j+=j&-j) modify(rt[j],1,len,h[b],-1),modify(rt[j],1,len,h[a],1);
        swap(h[a],h[b]);
        printf("%lld\n",ans);
    }
    return 0;
}

[BZOJ2141]排队

标签:show   uniq   markdown   main   大小   个数   unique   逆序   线段树   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8320455.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!