\[
\texttt{Description}
\]
给两个长度为 \(n\) 的数列 \(A\) 和 \(B\) 。
记 \(A\) 的逆序对(满足 \(x<y\),\(A_x>A_y\) 的数对 \((x,y)\) )对答案的贡献为 \(B_x+B_y\) 。
通俗地说,答案就是 \(\sum\limits_{x < y \ \& \ A_x > A_y}\) \(B_x+B_y\)。
一共 \(m\) 次交换,每次交换 \(A_x\) 和 \(A_y\) ,\(B_x\) 和 \(B_y\) 。
每次交换后,你都要给出答案。
\[
\texttt{Solution}
\]
- 是 CF785E 升级版,多加了 \(B\) 这一维度。
- 首先,对于初始序列的答案,显然可以用两个 \(\text{BIT}\) 来做,一个 \(\text{BIT}\) 维护值域内数的数量,一个 \(\text{BIT}\) 维护值域内数的 \(B\) 值和 ,像 \(\text{BIT}\) 求逆序对一样地,从后往前扫,考虑当前位置 \(x\) 上的数 \(A_x\) ,与 \(x+1\) 到 \(n\) 之间的 \(A_y\) 产生的逆序对对答案的贡献,记 \(C_1\) 为 \(A\) 值在 \([1,A_x-1]\) 内数的个数,记 \(C_2\) 为 \(A\) 值在 \([1,A_x-1]\) 内数的 \(B\) 值和,则对答案的贡献有 \(B_x \times C_1+C_2\) ,求完整个序列的答案的复杂度是 \(\mathcal{O(n \log n)}\) 的。
- 考虑交换怎么搞,对于任意两个位置 \(x,y\) ,我们考虑计算出交换 \(x,y\) 对答案造成的影响。
- 首先,交换 \(x,y\) 显然不会影响到 \([1,x-1]\) 和 \([y+1,n]\) 中的数与 \(A_x\) 或 \(A_y\) 产生的逆序对,因为相对位置是不变的。再者,对于 \(A_x\) 和 \(A_y\) 是否会形成逆序对,可以直接讨论一下 \(A_x\) 和 \(A_y\) 的大小关系。
- 于是我们只要考虑 \([x+1,y-1]\) 内的数与 \(A_x\) 和 \(A_y\) 的逆序对关系,我们可以视交换 \(x,y\) 为:在 \(x\) 处除去一个 \(A_x\) ,在 \(x\) 处增上一个 \(A_y\) ,在 \(y\) 处除去一个 \(A_y\) ,在 \(y\) 处增上一个 \(A_x\) 。
- 那么答案的变化应该为:
减去 " \(B_x\times\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([1,A_x-1]\) 的数的个数 \(+\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([1,A_x-1]\) 的数的 \(B\) 值和 " 。
加上 " \(B_y\times\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([1,A_y-1]\) 的数的个数 \(+\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([1,A_y-1]\) 的数的 \(B\) 值和 " 。
减去 " \(B_y\times\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([A_y+1,n]\) 的数的个数 \(+\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([A_y+1,n]\) 的数的 \(B\) 值和 " 。
加上 " \(B_x\times\) 区间 \([x+1,y-1]\) 内 \(A\) 值在 \([A_x+1,n]\) 的数的个数 \(+\) 区间 \([x+1,y-1]\) 内 \(A\) 值在\([A_x+1,n]\) 的数的 \(B\) 值和 " 。
- 我们发现更新答案需要查询 " 区间内的给定值域内的数的信息 " ,并且带修,可以用树套树来做(\(\text{BIT}\) 套权值线段树,线段树套权值线段树都可以)。
- \(\mathcal{O(n \log^2 n)}\) ,评测记录 。
\[
\texttt{Code}
\]
#include<cstdio>
#include<algorithm>
#define RI register int
using namespace std;
namespace IO
{
static char buf[1<<20],*fs,*ft;
inline char gc()
{
if(fs==ft)
{
ft=(fs=buf)+fread(buf,1,1<<20,stdin);
if(fs==ft)return EOF;
}
return *fs++;
}
#define gc() getchar()
inline int read()
{
int x=0,f=1;char s=gc();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
return x*f;
}
}using IO::read;
const int N=50100,MLOGNLOGN=20000000;
const int Mod=1e9+7;
void ckadd(long long &x,long long val)
{
x=((x+val)%Mod+Mod)%Mod;
}
int n,m;
long long a[N],b[N];
long long BIT[N][2]; // 0 个数 : 1 和
void BIT_add(int x,int k,int val)
{
for(;x<=n;x+=x&-x)ckadd(BIT[x][k],val);
}
long long BIT_ask(int x,int k)
{
long long ans=0;
for(;x;x-=x&-x)ckadd(ans,BIT[x][k]);
return ans;
}
long long ans;
int tot,root[N];
struct SegmentTree{
int lc,rc;
long long cnt;
long long sum;
}t[MLOGNLOGN];
int New()
{
tot++;
t[tot].lc=t[tot].rc=t[tot].cnt=0;
return tot;
}
void insert(int &p,int l,int r,int delta,int cnt,int sum)
{
if(!p)p=New();
ckadd(t[p].cnt,cnt);
ckadd(t[p].sum,sum);
if(l==r)return;
int mid=(l+r)/2;
if(delta<=mid)
insert(t[p].lc,l,mid,delta,cnt,sum);
else
insert(t[p].rc,mid+1,r,delta,cnt,sum);
}
void add(int pos,int delta,int cnt,int sum)
{
for(;pos<=n;pos+=pos&-pos)
insert(root[pos],1,n,delta,cnt,sum);
}
int lenA,addt[N];
int lenS,subt[N];
long long ask(int L,int R,int k,int s,int e) // 区间 [l,r] 类型 k 值域 [s,e]
{
if(e==0||s>e)
return 0;
long long res=0;
int l,r;
lenA=0;
for(RI i=R;i;i-=i&-i)addt[++lenA]=root[i];
lenS=0;
for(RI i=L-1;i;i-=i&-i)subt[++lenS]=root[i];
l=1,r=n;
while(true)
{
if(l==r)
{
for(RI i=1;i<=lenA;i++)ckadd(res,k?t[addt[i]].sum:t[addt[i]].cnt);
for(RI i=1;i<=lenS;i++)ckadd(res,k?-t[subt[i]].sum:-t[subt[i]].cnt);
break;
}
int mid=(l+r)/2;
if(e<=mid)
{
for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].lc;
for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].lc;
r=mid;
}
else
{
for(RI i=1;i<=lenA;i++)ckadd(res,k?t[t[addt[i]].lc].sum:t[t[addt[i]].lc].cnt);
for(RI i=1;i<=lenS;i++)ckadd(res,k?-t[t[subt[i]].lc].sum:-t[t[subt[i]].lc].cnt);
for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].rc;
for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].rc;
l=mid+1;
}
}
if(s==1)
return res;
lenA=0;
for(RI i=R;i;i-=i&-i)addt[++lenA]=root[i];
lenS=0;
for(RI i=L-1;i;i-=i&-i)subt[++lenS]=root[i];
l=1,r=n;
while(true)
{
if(l==r)
{
for(RI i=1;i<=lenA;i++)ckadd(res,k?-t[addt[i]].sum:-t[addt[i]].cnt);
for(RI i=1;i<=lenS;i++)ckadd(res,k?t[subt[i]].sum:t[subt[i]].cnt);
break;
}
int mid=(l+r)/2;
if(s-1<=mid)
{
for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].lc;
for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].lc;
r=mid;
}
else
{
for(RI i=1;i<=lenA;i++)ckadd(res,k?-t[t[addt[i]].lc].sum:-t[t[addt[i]].lc].cnt);
for(RI i=1;i<=lenS;i++)ckadd(res,k?t[t[subt[i]].lc].sum:t[t[subt[i]].lc].cnt);
for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].rc;
for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].rc;
l=mid+1;
}
}
return res;
}
void turn(int x,int y)
{
if(x>y)
swap(x,y);
if(x+1<=y-1)
{
ckadd(ans,-b[x]*ask(x+1,y-1,0,1,a[x]-1)-ask(x+1,y-1,1,1,a[x]-1));
ckadd(ans,-b[y]*ask(x+1,y-1,0,a[y]+1,n)-ask(x+1,y-1,1,a[y]+1,n));
ckadd(ans,b[y]*ask(x+1,y-1,0,1,a[y]-1)+ask(x+1,y-1,1,1,a[y]-1));
ckadd(ans,b[x]*ask(x+1,y-1,0,a[x]+1,n)+ask(x+1,y-1,1,a[x]+1,n));
}
if(a[x]>a[y])
ckadd(ans,-b[x]-b[y]);
else if(a[x]<a[y])
ckadd(ans,b[x]+b[y]);
add(x,a[x],-1,-b[x]);
add(y,a[y],-1,-b[y]);
swap(a[x],a[y]),swap(b[x],b[y]);
add(x,a[x],1,b[x]);
add(y,a[y],1,b[y]);
}
int main()
{
n=read(),m=read();
for(RI i=1;i<=n;i++)
a[i]=read(),b[i]=read(),
add(i,a[i],1,b[i]);
for(RI i=n;i;i--)
{
ckadd(ans,b[i]*BIT_ask(a[i]-1,0)+BIT_ask(a[i]-1,1));
BIT_add(a[i],0,1),BIT_add(a[i],1,b[i]);
}
while(m--)
{
int x=read(),y=read();
turn(x,y);
printf("%lld\n",ans);
}
return 0;
}
\[
\texttt{Thanks} \ \texttt{for} \ \texttt{watching}
\]
原文地址:https://www.cnblogs.com/cjtcalc/p/12431643.html