题目
描述
有\(n\)只熊,初始时坐标为\((x_i,y_i)\);
这些熊会按照标号依次吼叫,当第\(i\)只熊吼叫,其他熊会移动;
\((x_i,y_i)\)会移动到\((x_i \pm 1,y_i \pm 1)\)离吼叫的熊欧几里得距离最小的位置;
问当第\(i\)只熊生病了,不吼叫也不移动,其他的熊依次吼叫后的\(\sum_{i=1}^{n}x_iy_i\);
依次输出\(ans_i\);
范围
\(2 \le n \le 2.5 \times 10^5 \ , \ 1 \le x_i ,y_i \le 10^6\)
题解
$Part 1 $
横纵坐标独立,所以分别考虑每一维的情况;
设将熊按照坐标大小排序并差分,设\(d_i = x_i - x_{i-1},pos_i\)为熊离散后的下标;
那么操作可以看成找到\(pos_i\)之前的第一个不为\(0\)的数字\(--\),找到\(pos_i\)及之后第一个不为\(0\)的数字\(--\);
我们可以找到大家都好好的时候这样子的吼叫区间\((L_i,R_i)\);
容易发现他们是互相包含或者端点相接;
当第\(i\)熊不吼叫时,它减少的贡献初始也是\((L_i,R_i)\),但是 $ i+1 \to m $ 的熊的吼叫区间会影响$ (L_i,R_i) $ ;
可以发现最终\(L_i,R_i\)也是一个区间,只要统计了所有最终这样的区间就可以统计答案;
$Part 2 $
考虑第\(j\)只熊吼叫时,\((L_j,R_j)(j>i)\)依次对\((L_i,R_i)\)的影响;
- 当且仅当 $ L_j \le L_i , R_i \le R_j $ 时 $ i $ 会被 $ j $ 影响;
- 1.若\(R_i<pos_j\),则新的区间为\((L_j,L_i)\);
- 2.若\(L_i >= pos_j\),则新的区间为\((R_i,R_j)\);
- 3.若\(L_i<pos_j且pos_j<=R_i\) , 则新的区间为\((L_j,R_j)\);
考虑如何维护这些区间的变化;
由于一次变化后,所有被影响到的区间一定是在左端点或者右端点;
在每个区间的左端点记录\(Right\)集合,对右端点记录\(Left\)集合;
对于在\(pos_i\)左边的区间的\(Left\),显然可以直接加到\(j\)的\(Right\)上;
右边区间的\(Right\)同理;
对于左边区间的\(Right\),可以发现在变化过后所有的区间变成了相同的区间,并查集合并即可
右边区间的\(Left\)和跨越\(pos_i\)的的区间同理;
上述过程可以简单链表+并查集实现,查找包含的区间可以用\(set\)维护;
$Part 3 $
考虑如何求最终的答案;
先预处理一个正常情况下的答案;
对于每个熊,设正常情况下最终位置为:\((x_i,y_i)\),相当于变成了\((x_i \pm 1, y_i \pm 1)\);
\((x_i+a)(y_i+b) - x_iy_i \ = \ ax_i + by_i + ab\);
前缀和维护\(ax_i\)和\(by_i\)再加个二维数点维护\(ab\)即可;
。。。。。。
#include<bits/stdc++.h> #define ll long long #define mk make_pair #define fir first #define sec second using namespace std; const int N=1000010; int n,px[N],py[N],idx[N],idy[N],dx[N],dy[N],p[N],rk[N]; int fa[N],pre[N],nxt[N],nt[N],sz,sta[N],top; int Lx[N],Rx[N],Ly[N],Ry[N],Lx0[N],Rx0[N],Ly0[N],Ry0[N],tx[N],ty[N],rkx[N],rky[N]; ll sumx[N],sumy[N],pre_ans; inline char gc(){ static char*p1,*p2,s[1000000]; if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); return(p1==p2)?EOF:*p1++; } inline int rd(){ int x=0;char c=gc(); while(c<'0'||c>'9')c=gc(); while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); return x; } inline bool cmpx(const int&a,const int&b){return px[a]<px[b];} inline bool cmpy(const int&a,const int&b){return py[a]<py[b];} int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int find_nxt(int x){return nxt[x]==x?x:nxt[x]=find_nxt(nxt[x]);} int find_pre(int x){return pre[x]==x?x:pre[x]=find_pre(pre[x]);} struct table{int hd,tl;}; void link(table&A,int x){ if(!A.hd){nt[A.hd=A.tl=x]=0;return;} nt[A.tl]=x;nt[A.tl=x]=0; } void link(table&A,table B){ if(!B.hd)return; if(!A.hd){A=B;return;} nt[A.tl]=B.hd;A.tl=B.tl; } struct inter{ int l,r; table L,R; void init(const int&id,const int&tl,const int&tr){ L.hd=R.hd=L.tl=R.tl=0; l=tl,r=p[id]=tr; // link(L,id); } }A[N]; typedef pair<int,int>pii; set<pii>S; set<pii>::iterator st,ed,I; void solve(const int*id,int*d,int*L,int*R,int*L0,int*R0){ d[0]=d[n]=n+1; for(int i=0;i<=n;++i)pre[i]=nxt[i]=fa[i]=i; for(int i=1;i<n;++i)if(!d[i])pre[i]=i-1,nxt[i]=i+1; for(int i=1;i<=n;++i){ int pos=id[i]-1,l=find_pre(pos),r=find_nxt(pos+1),f; L0[i]=l;R0[i]=r; d[l]--;if(!d[l])pre[l]=l-1,nxt[l]=l+1; d[r]--;if(!d[r])pre[r]=r-1,nxt[r]=r+1; A[i].init(i,l,r); st=S.lower_bound(mk(l,0)); ed=S.lower_bound(mk(r,0)); inter&tmp=A[i]; for(I=st;I!=ed;++I){ inter now=A[(*I).sec]; if(now.r<=pos){ if(now.L.hd){ p[f=now.L.hd]=now.l; for(int j=nt[f];j;j=nt[j])fa[find(j)]=find(f); link(tmp.L,f); } link(tmp.L,now.R); }else if(now.l>pos){ link(tmp.R,now.L); if(now.R.hd){ p[f=now.R.hd]=now.r; for(int j=nt[f];j;j=nt[j])fa[find(j)]=find(f); link(tmp.R,f); } }else{ int j=now.L.hd; if(j&&p[j]<=pos){ p[f=j]=now.l; for(j=nt[f];j&&p[j]<=pos;j=nt[j])fa[find(j)]=find(f); link(tmp.L,f); } for(;j;j=nt[j])fa[find(j)]=find(i); for(j=now.R.hd;j&&p[j]<=pos;j=nt[j])fa[find(j)]=find(i); if(j){ p[f=j]=now.r; for(j=nt[f];j;j=nt[j])fa[find(j)]=find(f); link(tmp.R,f); } } } link(tmp.L,i); S.erase(st,ed); S.insert(mk(l,i)); } st=S.begin();ed=S.end(); for(I=st;I!=ed;++I){ inter tmp=A[(*I).sec]; for(int j=tmp.L.hd;j;j=nt[j])L[j]=tmp.l,R[j]=p[j]; for(int j=tmp.R.hd;j;j=nt[j])R[j]=tmp.r,L[j]=p[j]; } S.erase(st,ed); for(int i=1;i<=n;++i)if(find(i)!=i)L[i]=L[fa[i]],R[i]=R[fa[i]]; } struct tree{ int sz,rt[N],ls[N*20],rs[N*20],sum[N*20]; void insert(int&k,int lst,int l,int r,int x){ sum[k=++sz]=sum[lst]+1; ls[k]=ls[lst],rs[k]=rs[lst]; if(l==r)return; int mid=l+r>>1; if(x<=mid)insert(ls[k],ls[lst],l,mid,x); else insert(rs[k],rs[lst],mid+1,r,x); } int que(int k,int lst,int l,int r,int x,int y){ if(l==x&&r==y)return sum[k]-sum[lst]; int mid=l+r>>1; if(y<=mid)return que(ls[k],ls[lst],l,mid,x,y); else if(x>mid)return que(rs[k],rs[lst],mid+1,r,x,y); else return que(ls[k],ls[lst],l,mid,x,mid)+que(rs[k],rs[lst],mid+1,r,mid+1,y); } void insert(int x,int y){insert(rt[x],rt[x-1],1,n,y);} int query(int lx,int rx,int ly,int ry){ if(lx>rx||ly>ry)return 0; return que(rt[rx],rt[lx-1],1,n,ly,ry); } }T; void pre_cal(){ for(int i=0;i<=n;++i)dx[i]=dy[i]=0; for(int i=1;i<=n;++i)dx[Rx0[i]+1]--,dy[Lx0[i]]++; for(int i=1;i<=n;++i)dx[i]+=dx[i-1],dy[n-i+1]+=dy[n-i+2]; for(int i=1;i<=n;++i)px[idx[i]]+=dx[i]+dy[i]; for(int i=0;i<=n;++i)dx[i]=dy[i]=0; for(int i=1;i<=n;++i)dx[Ry0[i]+1]--,dy[Ly0[i]]++; for(int i=1;i<=n;++i)dx[i]+=dx[i-1],dy[n-i+1]+=dy[n-i+2]; for(int i=1;i<=n;++i)py[idy[i]]+=dx[i]+dy[i]; for(int i=1;i<=n;++i)pre_ans+=1ll*px[i]*py[i]; for(int i=1;i<=n;++i)sumx[i]=px[idy[i]]+sumx[i-1],sumy[i]=py[idx[i]]+sumy[i-1]; } ll cal(int id,int lx,int rx,int ly,int ry){ ll tmp=pre_ans; tmp-=sumy[lx]; tmp+=sumy[n]-sumy[rx]; tmp-=sumx[ly]; tmp+=sumx[n]-sumx[ry]; tmp+=T.query(1,lx,1,ly); tmp-=T.query(1,lx,ry+1,n); tmp-=T.query(rx+1,n,1,ly); tmp+=T.query(rx+1,n,ry+1,n); int fgx=rkx[id]<=lx?-1:rkx[id]>rx?1:0; int fgy=rky[id]<=ly?-1:rky[id]>ry?1:0; tmp-=(ll)(px[id]+fgx)*(py[id]+fgy); tmp+=(ll)tx[id]*ty[id]; return tmp; } int main(){ freopen("bear.in","r",stdin); freopen("bear.out","w",stdout); n=rd(); for(int i=1;i<=n;++i){ tx[i]=px[i]=rd(); ty[i]=py[i]=rd(); idx[i]=idy[i]=fa[i]=i; } sort(idx+1,idx+n+1,cmpx); sort(idy+1,idy+n+1,cmpy); for(int i=1;i<=n;++i){ rkx[idx[i]]=i; rky[idy[i]]=i; dx[i-1]=px[idx[i]]-px[idx[i-1]]; dy[i-1]=py[idy[i]]-py[idy[i-1]]; } for(int i=1;i<=n;++i)T.insert(i,rky[idx[i]]); memset(Lx,-1,sizeof(Lx)); memset(Rx,-1,sizeof(Rx)); memset(Ly,-1,sizeof(Ly)); memset(Ry,-1,sizeof(Ry)); solve(rkx,dx,Lx,Rx,Lx0,Rx0); solve(rky,dy,Ly,Ry,Ly0,Ry0); pre_cal(); for(int i=1;i<=n;++i){ ll ans = cal(i,Lx[i],Rx[i],Ly[i],Ry[i]); printf("%lld\n",ans); } return 0; }