代码源 扫描线权值线段树 板子

Bertha 。 2024-03-17 14:51 180阅读 0赞

矩形面积并(存档)

矩形面积并 - 题目 - Daimayuan Online Judge

题意:

a357df77b12e4c55a7a0860ea9f61887.png

Code(存档,还没写完):

  1. #include <bits/stdc++.h>
  2. #define y1 Y1
  3. #define int long long
  4. using namespace std;
  5. const int mxn=2e5+10;
  6. const int mxe=2e5+10;
  7. const int mod=1e9+7;
  8. struct info{
  9. int minv,mincnt;
  10. };
  11. info operator+(const info &l,const info &r){
  12. info res;
  13. res.minv=min(l.minv,r.minv);
  14. if(l.minv==r.minv) res.mincnt=l.mincnt+r.mincnt;
  15. else if(l.minv<r.minv) res.mincnt=l.mincnt;
  16. else res.mincnt=r.mincnt;
  17. return res;
  18. }
  19. struct Segtree{
  20. int t;
  21. info val;
  22. }tree[mxe<<4];
  23. vector<int> Vx;
  24. vector<array<int,4> > V;
  25. int N;
  26. int x1,x2,y1,y2;
  27. void pushup(int rt){
  28. tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
  29. }
  30. void build(int rt,int l,int r){
  31. if(l==r){
  32. tree[rt]={0,Vx[r]-Vx[r-1]};
  33. return;
  34. }
  35. int mid=l+r>>1;
  36. build(rt<<1,l,mid);
  37. build(rt<<1|1,mid+1,r);
  38. pushup(rt);
  39. }
  40. void settag(int rt,int tag){
  41. tree[rt].val.minv=tree[rt].val.minv+tag;
  42. tree[rt].t=tree[rt].t+tag;
  43. }
  44. void pushdown(int rt){
  45. if(tree[rt].t){
  46. settag(rt<<1,tree[rt<<1].t);
  47. settag(rt<<1|1,tree[rt<<1|1].t);
  48. tree[rt].t=0;
  49. }
  50. }
  51. void modify(int rt,int l,int r,int x,int y,int k){
  52. if(x<=l&&r<=y){
  53. tree[rt].t+=k;
  54. tree[rt].val.mincnt+=(r-l+1)*k;
  55. return;
  56. }
  57. pushdown(rt);
  58. int mid=l+r>>1;
  59. if(x<=mid) modify(rt<<1,l,mid,x,y,k);
  60. if(y>mid) modify(rt<<1|1,mid+1,r,x,y,k);
  61. pushup(rt);
  62. }
  63. void solve(){
  64. cin>>N;
  65. for(int i=1;i<=N;i++){
  66. cin>>x1>>x2>>y1>>y2;
  67. Vx.push_back(x1);
  68. Vx.push_back(x2);
  69. V.push_back({y1,1,x1,x2});
  70. V.push_back({y2,-1,x1,x2});
  71. }
  72. sort(V.begin(),V.end());
  73. sort(Vx.begin(),Vx.end());
  74. Vx.erase(unique(Vx.begin(),Vx.end()),Vx.end());
  75. int m=Vx.size()-1;
  76. int last=0;
  77. build(1,1,m);
  78. int totlen=tree[1].val.mincnt;
  79. int ans=0;
  80. for(auto it:V){
  81. int cov=totlen;
  82. if(tree[1].val.minv==0){
  83. cov=totlen-tree[1].val.mincnt;
  84. }
  85. ans+=(it[0]-last)*cov;
  86. last=it[0];
  87. int x1=lower_bound(Vx.begin(),Vx.end(),it[2])-Vx.begin()+1;
  88. int x2=lower_bound(Vx.begin(),Vx.end(),it[3])-Vx.begin();
  89. if(x1>x2) continue;
  90. modify(1,1,N,x1,x2,it[1]);
  91. }
  92. cout<<ans<<'\n';
  93. }
  94. signed main(){
  95. ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  96. int __=1;//cin>>__;
  97. while(__--)solve();return 0;
  98. }

二维数点

题意:

7e7d3f1426af49c4b64bd7211f21aa58.png

c9c971b21b684cf686644d847fa55709.png

思路:

二维数点本质上也是扫描线,即枚举一个指针,去枚举一棵线段树

在这里,枚举纵坐标,线段树维护一个横坐标区间内有多少点

这道题也用了离线的思想,将询问排序,在维护线段树的同时维护答案数组

具体的看代码就懂

Code:

  1. #include <bits/stdc++.h>
  2. #define y1 Y1
  3. #define low(x) (x&(-x))
  4. #define int long long
  5. using namespace std;
  6. const int mxn=2e5+10;
  7. const int mxe=2e5+10;
  8. const int mod=1e9+7;
  9. vector<int> Vx;
  10. vector<array<int,4> > V;
  11. int N,Q,x,y;
  12. int x1,x2,y1,y2;
  13. int ans[mxn],tr[mxn];
  14. void add(int x,int k){
  15. for(int i=x;i<=N;i+=low(i)) tr[i]+=k;
  16. }
  17. int sum(int x){
  18. int res=0;
  19. for(int i=x;i;i-=low(i)) res+=tr[i];
  20. return res;
  21. }
  22. void solve(){
  23. cin>>N>>Q;
  24. for(int i=1;i<=N;i++){
  25. cin>>x>>y;
  26. Vx.push_back(x);
  27. V.push_back({y,0,x});
  28. }
  29. for(int i=1;i<=Q;i++){
  30. cin>>x1>>x2>>y1>>y2;
  31. V.push_back({y1-1,2,x1-1,i});
  32. V.push_back({y2,2,x2,i});
  33. V.push_back({y2,1,x1-1,i});
  34. V.push_back({y1-1,1,x2,i});
  35. }
  36. sort(V.begin(),V.end());
  37. sort(Vx.begin(),Vx.end());
  38. Vx.erase(unique(Vx.begin(),Vx.end()),Vx.end());
  39. for(auto it:V){
  40. if(it[1]==0){
  41. int xx=lower_bound(Vx.begin(),Vx.end(),it[2])-Vx.begin()+1;
  42. add(xx,1);
  43. }else{
  44. int xx=upper_bound(Vx.begin(),Vx.end(),it[2])-Vx.begin()+1-1;
  45. int t=sum(xx);
  46. if(it[1]==1) ans[it[3]]-=t;
  47. else ans[it[3]]+=t;
  48. }
  49. }
  50. for(int i=1;i<=Q;i++) cout<<ans[i]<<'\n';
  51. }
  52. signed main(){
  53. ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  54. int __=1;//cin>>__;
  55. while(__--)solve();return 0;
  56. }

区间不同数之和

题意:

f967c55c644840df86d3dd656c5b20f5.png

43871f50bef34a18b254eebf7dcc890e.png

思路:

枚举一个指针,单独考虑每个元素的贡献

对于每个元素都去每个区间更新贡献,这些区间指的是a[r]只出现一次的所有区间,同时维护离线了的答案区间

枚举+序列DS=扫描线

Code:

  1. #include <bits/stdc++.h>
  2. #define low(x) (x&(-x))
  3. #define int long long
  4. using namespace std;
  5. const int mxn=2e5+10;
  6. const int mxe=2e5+10;
  7. const int mod=1e9+7;
  8. vector<pair<int,int> > V[mxn];
  9. int N,Q,l,r;
  10. int tr[mxn];
  11. int a[mxn],pre[mxn],ans[mxn];
  12. void add(int x,int k){
  13. for(int i=x;i<=N;i+=low(i)) tr[i]+=k;
  14. }
  15. int sum(int x){
  16. int res=0;
  17. for(int i=x;i;i-=low(i)) res+=tr[i];
  18. return res;
  19. }
  20. void solve(){
  21. cin>>N>>Q;
  22. for(int i=1;i<=N;i++){
  23. cin>>a[i];
  24. }
  25. for(int i=1;i<=Q;i++){
  26. cin>>l>>r;
  27. V[r].push_back({l,i});
  28. }
  29. //枚举一个指针,单独考虑每个元素的贡献
  30. //对于每个元素都去每个区间更新贡献,这些区间指的是a[r]只出现一次的所有区间,同时维护离线了的答案区间
  31. //枚举+序列DS=扫描线
  32. for(int r=1;r<=N;r++){
  33. int p=pre[a[r]];
  34. add(p+1,a[r]);
  35. add(r+1,-a[r]);
  36. pre[a[r]]=r;
  37. for(auto it:V[r]) ans[it.second]=sum(it.first);
  38. }
  39. for(int i=1;i<=Q;i++) cout<<ans[i]<<'\n';
  40. }
  41. signed main(){
  42. ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  43. int __=1;//cin>>__;
  44. while(__--)solve();return 0;
  45. }

发表评论

表情:
评论列表 (有 0 条评论,180人围观)

还没有评论,来说两句吧...

相关阅读