4.2 模拟总结
前言
50pts
50+0+0
令人諤諤。
策略出了很大的問題。
T2暴力寫一些應該還是可以拿個50左右的分數的。
然而一直在扣T1…
T1一開始方向就有問題,不太可能做出來了。。。
講講T1吧。
T1還是挺巧妙的。
把有交的矩形連邊。
考慮一個三元組,無非四種情況:
我們要算第一種,就嘗試用 CneC_n^eCne? 減去234。
設點的度數為 did_idi?,那么我們發現 12∑di(n?di?1)\frac 1 2\sum d_i(n-d_i-1)21?∑di?(n?di??1) 就恰好把二三都統計了一遍。
那么如何求度數呢?
考慮對于 iii 尋找有交的矩形 jjj,分兩種情況:
分別用掃描線計算即可。
如果我們直接橫坐標掃描線,縱坐標區間求和,那么每一個有交的矩形都會統計交矩形的高度次,那么我們把所有的矩形上邊界-1,再算一次,前后之差就是我們需要的結果。
然后考慮如何統計三元環。
也是使用掃描線,令新加入的矩形強制為三元環中左端點最大的矩形。
那么剩下的需要任取兩個,方案數是 Cx2C_x^2Cx2?。
那么我們就需要區間加,區間維護 ∑Cx2\sum C_x^2∑Cx2?。
Cx2=x(x?1)2=12(x2?x)C_x^2=\dfrac{x(x-1)}{2}=\dfrac1 2 (x^2-x)Cx2?=2x(x?1)?=21?(x2?x),維護和與平方和即可。
和前面類似的,也需要把上邊界-1后答案做差來容斥。
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") using namespace std;const int N=8e5+100; const int mod=998244353; inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int n; bool F=0; struct node{int l,r,u,d; }p[N]; int q[N],cnt; struct ope{int op,l,r,pos,id,w;bool operator < (const ope oth)const{if(pos!=oth.pos) return pos<oth.pos;else return op<oth.op;} }o[N]; int num; ll f1[N],f2[N]; inline void add(int p,int w){int ori=p;for(;p<=cnt;p+=p&-p){f1[p]+=w;f2[p]+=ori*w;} } inline ll ask(int p){ll res(0),ori=p;for(;p;p-=p&-p){res+=(ori+1)*f1[p]-f2[p];}return res; } ll du[N]; //會判斷和自己相交 void work1(int w){memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));num=0;for(int i=1;i<=n;i++){o[++num]=(ope){1,p[i].d,p[i].u,p[i].l,i,1};o[++num]=(ope){2,p[i].d,p[i].u,p[i].l-1,i,-1};o[++num]=(ope){2,p[i].d,p[i].u,p[i].r,i,1};}sort(o+1,o+1+num);for(int i=1;i<=num;i++){if(o[i].op==1){add(o[i].l,o[i].w);add(o[i].r+1,-o[i].w);}else{du[o[i].id]+=w*o[i].w*(ask(o[i].r)-ask(o[i].l-1));}}return; } //會判斷和自己相交 void work2(int w){memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));num=0;for(int i=1;i<=n;i++){o[++num]=(ope){1,p[i].d,p[i].u,p[i].l,i,1};o[++num]=(ope){1,p[i].d,p[i].u,p[i].r+1,i,-1};o[++num]=(ope){2,p[i].d,p[i].u,p[i].l,i,1};}sort(o+1,o+1+num);for(int i=1;i<=num;i++){if(o[i].op==1){add(o[i].l,o[i].w);add(o[i].r+1,-o[i].w);}else{du[o[i].id]+=w*o[i].w*(ask(o[i].r)-ask(o[i].l-1));}}return; } ll S; #define mid ((l+r)>>1) #define ls (k<<1) #define rs (k<<1|1) ll cub[N<<2],sq[N<<2],sum[N<<2],ans[N<<2],laz[N<<2]; inline void pushup(int k){cub[k]=cub[ls]+cub[rs];sq[k]=sq[ls]+sq[rs];sum[k]=sum[ls]+sum[rs];ans[k]=ans[ls]+ans[rs];return; } inline void add(int k,int l,int r,ll w){ll o=r-l+1;cub[k]+=3*w*sq[k]+3*w*w*sum[k]+o*w*w*w;sq[k]+=2*w*sum[k]+o*w*w;sum[k]+=o*w;ans[k]=(sq[k]-sum[k])/2;laz[k]+=w;return; } inline void pushdown(int k,int l,int r){ll o=laz[k];laz[k]=0;if(!o) return;add(ls,l,mid,o);add(rs,mid+1,r,o);return; } void build(int k,int l,int r){cub[k]=sq[k]=sum[k]=ans[k]=laz[k]=0;if(l==r) return;build(ls,l,mid);build(rs,mid+1,r);return; } //ll val[N]; void change(int k,int l,int r,int x,int y,int w){ if(x>y) return;//for(int i=x;i<=y;i++) val[i]+=w;//return;if(x<=l&&r<=y){add(k,l,r,w);return;}pushdown(k,l,r);if(x<=mid) change(ls,l,mid,x,y,w);if(y>mid) change(rs,mid+1,r,x,y,w);pushup(k); } ll ask(int k,int l,int r,int x,int y){if(x>y) return 0;//ll ans(0);//for(int i=x;i<=y;i++) ans+=val[i]*(val[i]-1)*(val[i]-2)/6;//return ans;if(x<=l&&r<=y) return ans[k];pushdown(k,l,r);ll res(0);if(x<=mid) res+=ask(ls,l,mid,x,y);if(y>mid) res+=ask(rs,mid+1,r,x,y);return res; }void work3(int w){num=0;build(1,1,cnt);for(int i=1;i<=n;i++){o[++num]=(ope){1,p[i].d,p[i].u,p[i].l+1,i,1};o[++num]=(ope){1,p[i].d,p[i].u,p[i].r+1,i,-1};o[++num]=(ope){2,p[i].d,p[i].u,p[i].l,i,1};}sort(o+1,o+1+num);for(int i=1;i<=num;i++){if(o[i].op==1){change(1,1,cnt,o[i].l,o[i].r,o[i].w);if(F) printf("change: (%d %d) w=%d\n",o[i].l,o[i].r,o[i].w);}else{S+=w*o[i].w*ask(1,1,cnt,o[i].l,o[i].r);if(F) printf("ask: (%d %d) res=%lld\n",o[i].l,o[i].r,ask(1,1,cnt,o[i].l,o[i].r));}}if(F) printf("S=%lld\n",S);return; }signed main(){//#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);// freopen("a.out","w",stdout);//#endifn=read();for(int i=1;i<=n;i++){p[i].l=read();p[i].r=read();p[i].d=read();p[i].u=read();q[++cnt]=p[i].l;q[++cnt]=p[i].r;q[++cnt]=p[i].d;q[++cnt]=p[i].u;}sort(q+1,q+1+cnt);cnt=unique(q+1,q+1+cnt)-q-1;for(int i=1;i<=n;i++){p[i].l=lower_bound(q+1,q+1+cnt,p[i].l)-q;p[i].r=lower_bound(q+1,q+1+cnt,p[i].r)-q;p[i].d=lower_bound(q+1,q+1+cnt,p[i].d)-q;p[i].u=lower_bound(q+1,q+1+cnt,p[i].u)-q;if(F)printf("%d %d %d %d\n",p[i].l,p[i].r,p[i].d,p[i].u);}work1(1);if(F) for(int i=1;i<=n;i++) printf("i=%d du=%lld\n",i,du[i]);work2(1);work3(1);if(F) for(int i=1;i<=n;i++) printf("i=%d du=%lld\n",i,du[i]);for(int i=1;i<=n;i++) p[i].u--; work1(-1);work2(-1);work3(-1); for(int i=1;i<=n;i++) du[i]-=2;if(F) for(int i=1;i<=n;i++) printf("i=%d du=%lld\n",i,du[i]);ll ans=1ll*n*(n-1)*(n-2)/6-S,add(0);for(int i=1;i<=n;i++){add+=1ll*du[i]*(n-du[i]-1);}add>>=1;//printf("S=%lld\n",S);printf("%lld\n",ans-add);return 0; } /**/總結
- 上一篇: 3.28模拟
- 下一篇: 怎么上扣扣空间里的沃邮箱(扣扣空间怎么找