• [BZOJ2141]排队


    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
    ",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
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java B/S开发模式漫谈 (转)
    struts 使用多个配置文件 strutsconfig.xml
    java 验证邮箱格式正确性、验证字符串是否为数字
    Java获取各种常用时间方法
    创建HttpServlet的基本步骤
    struts1.x 配置文件之——web.xml详解
    最常用的JAVA包
    字符串转换为日期时间格式
    struts1.x 配置文件详解
    看看别人的博客,经验总结,很宝贵
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8320455.html
Copyright © 2020-2023  润新知