2018湖南省程式設計競賽E題 動態開點線段樹
阿新 • • 發佈:2018-12-17
csu還沒好,題目連線暫時沒有,省賽時沒寫出這個題,確實是線段樹水平太菜了,現在又想到了這個題,我靠水題。
思路:這個題說白了就是求最大1 到1e9這個區間有多少個點被覆蓋,普通線段樹空間肯定不行,不過可以用動態開點解決,每次更新最多新花幾十個節點的空間,1e5次更新,最多隻需幾百萬的空間足夠,解決了問題這個就是水題了。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int maxn=5e6; int ls[maxn],rs[maxn],sum[maxn],Min[maxn],Max[maxn]; int ls2[maxn],rs2[maxn],sum2[maxn],Min2[maxn],Max2[maxn]; int n,m,cnt,cnt2; void pushup(int o,int ls,int rs) { Min[o]=min(Min[ls],Min[rs]); Max[o]=max(Max[ls],Max[rs]); sum[o]=sum[ls]+sum[rs]; } void up(int& o,int l,int r,int ql,int qr) { if(!o)o=++cnt; if(Min[o]==1)return; int mid=(l+r)/2; if(l>=ql&&r<=qr) { if(Max[o]==0) { Max[o]=Min[o]=1; sum[o]=r-l+1; return; } if(Min[ls[o]]==0)up(ls[o],l,mid,ql,qr); if(Min[rs[o]]==0)up(rs[o],mid+1,r,ql,qr); pushup(o,ls[o],rs[o]); } if(ql<=mid)up(ls[o],l,mid,ql,qr); if(qr>mid)up(rs[o],mid+1,r,ql,qr); pushup(o,ls[o],rs[o]); } void pushup2(int o,int ls,int rs) { Min2[o]=min(Min2[ls],Min2[rs]); Max2[o]=max(Max2[ls],Max2[rs]); sum2[o]=sum2[ls]+sum2[rs]; } void up2(int& o,int l,int r,int ql,int qr) { if(!o)o=++cnt2; if(Min2[o]==1)return; int mid=(l+r)/2; if(l>=ql&&r<=qr) { if(Max2[o]==0) { Max2[o]=Min2[o]=1; sum2[o]=r-l+1; return; } if(Min2[ls2[o]]==0)up2(ls2[o],l,mid,ql,qr); if(Min2[rs2[o]]==0)up2(rs2[o],mid+1,r,ql,qr); pushup2(o,ls2[o],rs2[o]); } if(ql<=mid)up2(ls2[o],l,mid,ql,qr); if(qr>mid)up2(rs2[o],mid+1,r,ql,qr); pushup2(o,ls2[o],rs2[o]); } int main() { int op,a,b,q; while(~scanf("%d%d%d",&n,&m,&q)) { cnt=cnt2=0; int rt=0,rt2=0; while(q--) { scanf("%d%d%d",&op,&a,&b); if(op==1) up(rt,1,n,a,b); else up2(rt2,1,m,a,b); ll ans=1ll*sum[1]*m; ans+=1ll*sum2[1]*n; ans-=1ll*sum[1]*sum2[1]; ans=1ll*n*m-ans+1; if(sum[1]==0) ans=1ll*(m-sum2[1])*n+sum2[1]; if(sum2[1]==0) ans=1ll*(n-sum[1])*n+sum[1]; printf("%lld\n",ans); } for(int i=1;i<=cnt;i++) sum[i]=Min[i]=Max[i]=0; for(int i=1;i<=cnt2;i++) sum2[i]=Min2[i]=Max2[i]=0; } }