题目
描述
有(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 imes 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 o 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 ",ans); } return 0; }