标签:print lld 位置 query unique 数组 -- include 一个
这道题也就是一个动态逆序对嘛,本质上就是个查询区间排名
刚刚打了一道 [CQOI 2011]动态逆序对 用的线段树套平衡树,代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 101000
#include<cstdlib>
#define LL long long
#define lc(x) (x->ch[0])
#define rc(x) (x->ch[1])
#define size(x) ((x)?(x->size):0)
struct Treap{
Treap *ch[2];
int key,v;LL size;
Treap(int x=0){
v=x;ch[0]=ch[1]=NULL;size=1;key=rand();
}
}*root[N*4];
void turn(Treap *&rt,int d){
Treap *t=rt->ch[d^1];
rt->ch[d^1]=t->ch[d]; rt->size=size(lc(rt))+size(rc(rt))+1;
t->ch[d]=rt; t->size=size(lc(t))+size(rc(t))+1;
rt=t;
}
void insert(Treap *&rt,int x){
if(rt==NULL){
rt=new Treap(x);return;
}
int d=rt->v < x;
insert(rt->ch[d],x);
if(rt->ch[d]->key < rt->key) turn(rt,d^1);
if(rt) rt->size=size(lc(rt))+size(rc(rt))+1;
}
void del(Treap *&rt,int x){
if(rt->v == x){
if(lc(rt)&&rc(rt)){
int d=lc(rt)->key < rc(rt)->key;
turn(rt,d);del(rt->ch[d],x);
}
else{
Treap *t=NULL;
if(lc(rt)) t=lc(rt);
else t=rc(rt);
delete rt;rt=t;
}
}
else{
int d=rt->v < x;
del(rt->ch[d],x);
}
if(rt) rt->size=size(lc(rt))+size(rc(rt))+1;
}
int a[N],pos[N];
int n,m;
void build(int l,int r,int rt){
pos(i,l,r) insert(root[rt],a[i]);
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
LL pai(Treap *&rt,int x){
if(!rt) return 0;
if(rt->v >= x) return pai(lc(rt),x);
else return size(lc(rt))+1+pai(rc(rt),x);
}
LL query(int flag,int xl,int xr,int l,int r,int num,int rt){
if(l>=xl&&r<=xr){
if(flag) return pai(root[rt],num);
else return size(root[rt])-pai(root[rt],num);
}
int mid=(l+r)>>1;
int res(0);
if(xl<=mid) res+=query(flag,xl,xr,l,mid,num,rt<<1);
if(xr>mid) res+=query(flag,xl,xr,mid+1,r,num,rt<<1|1);
return res;
}
void Del(int pos,int x,int l,int r,int rt){
del(root[rt],x);
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) Del(pos,x,l,mid,rt<<1);
else Del(pos,x,mid+1,r,rt<<1|1);
}
LL ans;
inline int read(){
int sum(0);char ch=getchar();
while(ch<‘0‘||ch>‘9‘) ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘){
sum=sum*10+ch-‘0‘;
ch=getchar();
}
return sum;
}
int lowbit(int x){
return x&(-x);
}
int c[N];
void add(int x,int num){
while(x<=n){
c[x]+=num;x+=lowbit(x);
}
}
LL tot(int x){
LL res(0);
while(x>0){
res+=c[x];x-=lowbit(x);
}
return res;
}
int main(){
n=read();m=read();
pos(i,1,n){
a[i]=read();
pos[a[i]]=i;
}
build(1,n,1);
pos(i,1,n){
ans+=i-1-tot(a[i]-1);
add(a[i],1);
}
pos(i,1,m){
printf("%lld\n",ans);
int x;x=read();
if(pos[x]+1<=n) ans-=query(1,pos[x]+1,n,1,n,x,1);
if(pos[x]-1>=1) ans-=query(0,1,pos[x]-1,1,n,x,1);
Del(pos[x],x,1,n,1);
}
return 0;
}
但是常数过于巨大,导致COGS上卡半天常都没过去最后一个点,只是在内网A掉了(赞一发内网评测机)
对于这道题,选择了原来没打过的树状数组套平衡树(其实本质上都是一样的啦)
假如我们交换a和b的位置(a<b),那么对答案产生影响的就是[a+1,b-1]这一段区间了
ans=ans-(区间内>b的个数)+(区间内<b的个数)-(区间内<a的个数)+(区间内>a的个数)
然后还要考虑a和b本身的大小造成的贡献
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 20100
#define lc(x) (x->ch[0])
#define rc(x) (x->ch[1])
#define size(x) ((x)?(x->size):0)
int n,m;
int a[N];
struct Treap{
Treap *ch[2];
int key,v,size;
Treap(int x=0){ch[0]=ch[1]=NULL;key=rand();size=1;v=x;}
}*root[N];
void pushup(Treap *&rt){
rt->size=size(lc(rt))+size(rc(rt))+1;
}
void turn(Treap *&rt,int d){
Treap *t=rt->ch[d^1];
rt->ch[d^1]=t->ch[d];pushup(rt);
t->ch[d]=rt;pushup(t);
rt=t;
}
void insert(Treap *&rt,int x){
if(!rt){
rt=new Treap(x);
return;
}
int d=rt->v < x;
insert(rt->ch[d],x);
if(rt->ch[d]->key < rt->key) turn(rt,d^1);
if(rt) pushup(rt);
}
void del(Treap *&rt,int x){
if(rt->v==x){
if(lc(rt)&&rc(rt)){
int d=lc(rt)->key < rc(rt)->key;
turn(rt,d);del(rt->ch[d],x);
}
else{
Treap *t;
if(lc(rt)) t=lc(rt);
else t=rc(rt);
delete rt;rt=t;
}
}
else{
int d=rt->v < x;
del(rt->ch[d],x);
}
if(rt) pushup(rt);
}
int lowbit(int x){
return x&(-x);
}
int ans;
void add(int x,int num,int flag){
while(x<=n){
if(flag) insert(root[x],num);
else del(root[x],num);
x+=lowbit(x);
}
}
int pai_min(Treap *&rt,int num){
if(!rt) return 0;
if(rt->v >= num) return pai_min(lc(rt),num);
else return size(lc(rt))+1+pai_min(rc(rt),num);
}
int pai_max(Treap *&rt,int num){
if(!rt) return 0;
if(rt->v > num) return size(rc(rt))+1+pai_max(lc(rt),num);
else return pai_max(rc(rt),num);
}
int tot_max(int x,int num){
int sum(0);
while(x>0){
sum+=pai_max(root[x],num);
x-=lowbit(x);
}
return sum;
}
int tot_min(int x,int num){
int sum(0);
while(x>0){
sum+=pai_min(root[x],num);
x-=lowbit(x);
}
return sum;
}
vector<int> b;
int findx(int x){
return lower_bound(b.begin(),b.end(),x)-b.begin()+1;
}
int main(){
scanf("%d",&n);
pos(i,1,n){
scanf("%d",&a[i]);b.push_back(a[i]);
}
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end());
pos(i,1,n){
a[i]=findx(a[i]);add(i,a[i],1);
}
pos(i,1,n){
ans+=tot_max(i-1,a[i]);
}
scanf("%d",&m);
printf("%d\n",ans);
pos(i,1,m){
int x,y;scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
ans-=tot_max(y-1,a[y])-tot_max(x,a[y]);
ans+=tot_min(y-1,a[y])-tot_min(x,a[y]);
ans-=tot_min(y-1,a[x])-tot_min(x,a[x]);
ans+=tot_max(y-1,a[x])-tot_max(x,a[x]);
if(a[x]>a[y]) ans--;
else if(a[x]<a[y]) ans++;
add(x,a[x],0);add(x,a[y],1);
add(y,a[y],0);add(y,a[x],1);
swap(a[x],a[y]);
printf("%d\n",ans);
}
return 0;
}
谨以此纪念此类型树套树入门
[BZOJ 2141][国家集训队 2011]排队 树状数组套平衡树
标签:print lld 位置 query unique 数组 -- include 一个
原文地址:http://www.cnblogs.com/Hallmeow/p/7985739.html