zoukankan      html  css  js  c++  java
  • 【BZOJ2141】排队(CDQ分治)

    【BZOJ2141】排队(CDQ分治)

    题面

    题面以及树套树做法见这里

    题解

    大部分树套树/主席树这类题目都可以用整体二分/CDQ分治来做。

    这题考虑一下,在不考虑修改的情况下
    贡献是如何产生的?
    我们发现是个二位偏序问题(或者说是一个逆序对修改版本)
    现在有了一个修改,那么产生贡献的前提额外增加一个:时间。
    既然变成了一个三位偏序问题
    考虑(CDQ)分治

    按照时间分治,块内按照(x)排序,考虑左侧对右侧的贡献:
    维护当前数字(离散后)的一个值域树状数组
    因为贡献有当前点作为左端点和右端点的两部分
    所以,按照(x)正着加入树状数组一次,反着加入树状数组一次。
    就求一下在当前时间之前,产生贡献的值就行了。

    但是交换操作很不好办。
    我们可以把一个交换操作改成两个删除操作和两个插入操作。
    这样就可以交换的问题。

    一个额外要注意的问题:排序的时候,如果(x)相同,一定还要按照修改的值排序,因为小的值同样可以更新大的值,否则会错。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 22222
    #define lb(x) (x&(-x))
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Operator{int t,x,y,w,id;}q[MAX<<2],tmp[MAX<<2];
    bool operator<(Operator a,Operator b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
    int tot,len,S[MAX],a[MAX],n,m,tim;
    int c[MAX],ans[MAX];
    void add(int x,int w){while(x<=n)c[x]+=w,x+=lb(x);return;}
    int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lb(x);return ret;}
    void CDQ(int l,int r)
    {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	for(int i=l;i<=r;++i)
    		if(q[i].t<=mid)add(q[i].y,q[i].w);
    		else ans[q[i].id]+=q[i].w*(getsum(n)-getsum(q[i].y));
    	for(int i=l;i<=r;++i)
    		if(q[i].t<=mid)add(q[i].y,-q[i].w);
    	for(int i=r;i>=l;--i)
    		if(q[i].t<=mid)add(q[i].y,q[i].w);
    		else ans[q[i].id]+=q[i].w*getsum(q[i].y-1);
    	for(int i=l;i<=r;++i)if(q[i].t<=mid)add(q[i].y,-q[i].w);
    	int t1=l-1,t2=mid;
    	for(int i=l;i<=r;++i)
    		if(q[i].t<=mid)tmp[++t1]=q[i];
    		else tmp[++t2]=q[i];
    	for(int i=l;i<=r;++i)q[i]=tmp[i];
    	CDQ(l,mid);CDQ(mid+1,r);
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)a[i]=S[i]=read();
    	sort(&S[1],&S[n+1]);len=unique(&S[1],&S[n+1])-S-1;
    	for(int i=1;i<=n;++i)a[i]=lower_bound(&S[1],&S[len+1],a[i])-S;
    	for(int i=1;i<=n;++i)q[++tot]=(Operator){++tim,i,a[i],1,0};
    	n=len;m=read();
    	for(int i=1;i<=m;++i)
    	{
    		int x=read(),y=read();
    		q[++tot]=(Operator){++tim,x,a[y],+1,i};
    		q[++tot]=(Operator){++tim,y,a[x],+1,i};
    		q[++tot]=(Operator){++tim,x,a[x],-1,i};
    		q[++tot]=(Operator){++tim,y,a[y],-1,i};
    		swap(a[x],a[y]);
    	}
    	sort(&q[1],&q[tot+1]);
    	CDQ(1,tim);
    	printf("%d
    ",ans[0]);
    	for(int i=1;i<=m;++i)printf("%d
    ",ans[i]+=ans[i-1]);
    	return 0;
    }
    
    
  • 相关阅读:
    javascript实现优先队列
    javascript中的队列结构
    mysql及php命名规范
    javascript使用栈结构将中缀表达式转换为后缀表达式并计算值
    【转】感知哈希算法——找出相似的图片
    重新注册iis的.NET Framework版本
    Extjs GridPanel用法详解
    Extjs Window用法详解
    Extjs Form用法详解(适用于Extjs5)
    Extjs MVC开发模式详解
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8762938.html
Copyright © 2011-2022 走看看