BZOJ2141: 排队

本文介绍了一种利用分块技术和树状数组解决特定类型问题的方法。通过对输入数据进行离散化处理,将数据集分成多个块,并为每个块建立一个树状数组,从而有效地处理了涉及元素交换的问题。文章提供了详细的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2141

分块加树状数组。

离散化之后,每一个块建一个树状数组。交换x,y,与x左边的数和y右边的数无关,只需处理>x,<y的数。

话说还可以用树套树来写,不过常数太大,比分块加树状数组慢。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define inf 1<<30
 7 #define maxn 20005
 8 using namespace std;
 9 int n,m,nn,tot,ans,a[maxn],t[205][maxn];
10 struct fuck{int x,id;}c[maxn];
11 int read(){
12     int x=0,f=1; char ch;
13     for(ch=getchar();ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
14     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
15     return x*f;
16 }
17 bool comp(fuck a,fuck b){return a.x<b.x;}
18 int p(int x){return (x-1)/nn+1;}
19 void change(int f,int x,int y){for(int i=x;i<=tot;i+=i&-i) t[f][i]+=y;}
20 int query(int f,int x){int y=0;for(int i=x;i;i-=i&-i) y+=t[f][i];return y;}
21 int main(){
22     n=read(); nn=sqrt(n);
23     for(int i=1;i<=n;i++) c[i].x=read(),c[i].id=i;
24     sort(c+1,c+n+1,comp);
25     for(int i=1;i<=n;i++){
26         if(c[i].x!=c[i-1].x) ++tot;
27         a[c[i].id]=tot;
28     }
29     for(int i=n;i;i--){
30         ans+=query(0,a[i]-1);
31         change(0,a[i],1);
32     }
33     printf("%d\n",ans);
34     for(int i=1;i<=n;i++) change(p(i),a[i],1);
35     m=read();
36     int x,y;
37     while(m--){
38         x=read(); y=read(); if(x>y) swap(x,y);
39         for(int i=p(x)+1;i<p(y);i++){
40             ans-=query(i,a[x]-1); ans+=query(i,tot)-query(i,a[x]);
41             ans-=query(i,tot)-query(i,a[y]); ans+=query(i,a[y]-1);
42         }
43         for(int i=x+1;p(i)==p(x)&&i<y;i++){
44             if(a[i]<a[x]) ans--; if(a[i]>a[x]) ans++;
45             if(a[i]<a[y]) ans++; if(a[i]>a[y]) ans--;
46         }
47         if(p(x)!=p(y))
48         for(int i=y-1;p(i)==p(y);i--){
49             if(a[i]<a[x]) ans--; if(a[i]>a[x]) ans++;
50             if(a[i]<a[y]) ans++; if(a[i]>a[y]) ans--;
51         }
52         if(a[x]<a[y]) ans++; if(a[x]>a[y]) ans--;
53         change(p(x),a[x],-1); change(p(x),a[y],1);
54         change(p(y),a[y],-1); change(p(y),a[x],1);
55         swap(a[x],a[y]);
56         printf("%d\n",ans);
57     }
58     return 0;
59 }
View Code

 

转载于:https://www.cnblogs.com/longshengblog/p/5543508.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值