• 解题报告:luogu P6186/NOI ONLINE T2


    题目链接(1)P6186 [NOI Online 提高组]冒泡排序
    感觉(T2)最水了,可是还是没想出来。
    大概要先会逆序对,有个板子题,然而我考试之前还没做过。
    题目链接(2):P1908 逆序对
    树状数组还要离散化,直接归并好了。
    注意边界,否则(T)掉两行泪啊。

    (Code):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN=500005;
    int n,m,a[MAXN],b[MAXN],rt[MAXN];
    ll ans=0;
    inline int read()
    {
    	int x=0,w=1;
    	char c=getchar();
    	while(c<'0'||c>'9')
    	{
    		if(c=='-') w=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')
    	{
    		x=(x<<1)+(x<<3)+(c^'0');
    		c=getchar();
    	}
    	return x*w;
    }
    inline void print(int x)
    {
    	if(x<0) x=-x,putchar('-');
    	if(x>=10) print(x/10);
    	putchar(x%10^'0');
    }
    inline void qsort(int l,int r)
    {
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	qsort(l,mid),qsort(mid+1,r);
    	int i=l,j=mid+1,c=l-1;
    	while(i<=mid&&j<=r)
    	{
    		if(a[i]<=a[j]) rt[++c]=a[i++];
    		else rt[++c]=a[j++],ans+=(ll)(mid-i+1);
    	}
    	while(i<=mid) rt[++c]=a[i++];
    	while(j<=r) rt[++c]=a[j++];
    	for(register int i=l;i<=r;i++) a[i]=rt[i]; 
    }
    int main()
    {
    	n=read();
    	for(register int i=1;i<=n;i++) a[i]=read();
    	qsort(1,n);
    	printf("%lld",ans);
    	return 0;
    } 
    

    大概还要注意开(long;long)
    好了,进入正题。
    然后我们发现一个规律,每一轮冒泡排序使得每个数前面比他大的数减一(当然是在存在的前提下),对于每个数前面比他大的数,在归并时求出即可。
    注意是(1)(n)的排列,这样就不需要离散化了,可是我还是码了。
    用一棵线段树来维护下即可。
    注意交换时,分两种情况来讨论。
    *,东西太多了,还是看代码吧,我把没用的都删了,否则就有(5KB)了,(qwq).

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN=200005;
    const ll inf=2147483647;
    ll n,m,c[MAXN],num[MAXN];
    int b[MAXN];
    inline ll read()
    {
    	ll x=0,w=1;
    	char c=getchar();
    	while(c<'0'||c>'9')
    	{
    		if(c=='-') w=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')
    	{
    		x=(x<<1)+(x<<3)+(c^'0');
    		c=getchar();
    	}
    	return x*w;
    }
    struct node
    {
    	int id;
    	ll val;
    }at[MAXN],rt[MAXN],cnt[MAXN];
    bool cmp(node n,node m){return n.val<m.val;}
    inline void qsort(int l,int r)
    {
    	if(l>=r) return;
    	int mid=(l+r)>>1;
    	qsort(l,mid),qsort(mid+1,r);
    	int i=l,j=mid+1,c=l-1;
    	while(i<=mid&&j<=r)
    	{
    		if(at[i].val<=at[j].val) rt[++c]=at[i++];
    		else rt[++c]=at[j],cnt[at[j++].id].val+=(ll)(mid-i+1);
    	}
    	while(i<=mid) rt[++c]=at[i++];
    	while(j<=r) rt[++c]=at[j++];
    	for(register int i=l;i<=r;i++) at[i]=rt[i]; 
    }
    void pro()
    {
    	sort(cnt+1,cnt+n+1,cmp);
    	//这里的b数组代表原数组的逆序对数在所有的数中排老几; 
    	//这里的num数组代表线段树中第几个数在原数组中的位置。 
    	for(int i=1;i<=n;i++) b[cnt[i].id]=i,num[i]=cnt[i].id;
    	return;
    }
    struct tree
    {
    	ll minn,maxn,sum;
    	ll l,r;
    	tree(){maxn=sum=0,minn=inf;}
    }a[MAXN<<2];
    void update(int k)
    {
    	a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
    	a[k].maxn=max(a[k<<1].maxn,a[k<<1|1].maxn);
    	a[k].minn=min(a[k<<1].minn,a[k<<1|1].minn);
    	return;
    }
    void build(int k,ll l,ll r)
    {
    	ll mid=(l+r)>>1;
    	a[k].l=l,a[k].r=r;
    	if(a[k].l==a[k].r)
    	{
    		a[k].maxn=a[k].minn=a[k].sum=(ll)cnt[l].val;
    		return;
    	}
    	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
    	update(k);
    }
    //查找小x于等于的所有位置,返回右端点。 
    int lit_first(int k,ll x)
    {
    	if(a[k].l==a[k].r) return a[k].r;
    	if(x>=a[k<<1|1].minn) return lit_first(k<<1|1,x);
    	else return lit_first(k<<1,x);
    }
    //查询比大于等于x的第一个数,返回这个编码 
    int lit_second(int k,ll x)
    {
    	if(a[k].l==a[k].r) return a[k].l;
    	if(x<=a[k<<1].maxn) return lit_second(k<<1,x);
    	else return lit_second(k<<1|1,x);
    }
    //naive的区间和  
    ll query(int k,ll l,ll r)
    {
    	ll mid=(a[k].l+a[k].r)>>1;
    	if(a[k].l==l&&a[k].r==r) return a[k].sum;
    	if(r<=mid) return query(k<<1,l,r);
    	else if(l>=mid+1) return query(k<<1|1,l,r);
    	else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);	
    } 
    //单点修改,你值得拥有 
    //把x点搞成y 
    void turn(int k,ll x,ll y)
    {
    	ll mid=(a[k].l+a[k].r)>>1;
    	if(a[k].l==a[k].r)
    	{
    		a[k].sum=a[k].maxn=a[k].minn=(ll)y;
    		return;	
    	}
    	if(x<=mid) turn(k<<1,x,y);
    	else turn(k<<1|1,x,y);
    	update(k);
    } 
    ll flag;
    int k;
    int main()
    {
    	//freopen("data.in","r",stdin);
    	//freopen("baoli.out","w",stdout);
    	scanf("%lld%lld",&n,&m);
    	for(register int i=1;i<=n;i++) at[i].val=read(),c[i]=at[i].val,at[i].id=i;
    	qsort(1,n);
    	for(int i=1;i<=n;i++) cnt[i].id=i;
    	pro();
    
    	build(1,1,n);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%lld%d",&flag,&k);
    		if(flag==1)
    		{
    			if(c[k]<c[k+1])
    			{
    				swap(c[k],c[k+1]);
    				swap(b[k],b[k+1]);
    				num[b[k]]=k,num[b[k+1]]=k+1;
    				k+=1; 
    				ll now=query(1,b[k],b[k]);
    				int rr=lit_first(1,now);
    				if(b[k]==rr)
    				{
    					turn(1,b[k],now+1);
    					continue;
    				}
    				swap(b[k],b[num[rr]]);
    				swap(num[rr],num[b[num[rr]]]);
    				turn(1,b[k],now+1); 
    			}
    			else if(c[k]>c[k+1])
    			{
    				swap(c[k],c[k+1]);
    				swap(b[k],b[k+1]);
    				num[b[k]]=k,num[b[k+1]]=k+1;
    				ll now=query(1,b[k],b[k]);
    				int rr=lit_second(1,now); 
    				if(b[k]==rr)
    				{
    					turn(1,b[k],now-1);
    					continue;
    				}
    				swap(b[k],b[num[rr]]);
    				swap(num[rr],num[b[num[rr]]]);
    				turn(1,b[k],now-1); 
    			}
    		}
    		else if(flag==2)
    		{
    			if(k>=a[1].maxn)
    			{
    				printf("0
    ");
    				continue;
    			}
    			else if(k==0)
    			{
    				printf("%lld
    ",a[1].sum);
    				continue;
    			}
    			ll rr=lit_first(1,k);
    			printf("%lld
    ",query(1,rr+1,n)-(n-rr)*k);
    	 	}
    	}
    	return 0;
    } 
    
    

    每个函数都是有用的,反正给我(3.5h)我是写不出来。

  • 相关阅读:
    grep命令详解
    Git命令详解(一)-个人使用
    android intent和intent action大全
    android 监控EditText的变化
    第86章、系统服务之TELEPHONY_SERVICE(从零开始学Android)
    android中getSystemService详解
    关于android各种双卡手机获取imei,imsi的处置(mtk,展讯,高通等)
    Android 获取运营商信息(完整版)-解决高通,MTK等双卡问题
    Android 移动缩放的ImageView
    Android 读写SD卡的文件
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12454111.html
Copyright © 2020-2023  润新知