线段树双tag+差分数组——cf1208E

超、凢脫俗 2023-10-11 09:04 24阅读 0赞

写了一上午

  1. /*
  2. 对于每个数组a[],先排序然后从大到小把a[i]放进线段树更新
  3. 设a[i]的位置是pos,那么其可更新的区间是[pos,w-(li-pos)]
  4. 线段树结点保存
  5. tag=now表示当前区间已经被更新满了,无需再往下更新
  6. flag=now表示当前区间被更新过
  7. flag=now-1表示当前区间从未被更新过,可以直接进行覆盖
  8. */
  9. #include<bits/stdc++.h>
  10. #include<vector>
  11. using namespace std;
  12. #define N 1000005
  13. #define ll long long
  14. ll ans[N];
  15. ll n,w;
  16. struct Node{ll pos,a;};
  17. int cmp(Node a,Node b){
  18. return a.a>b.a;}
  19. vector<Node>v[N];
  20. #define lson l,m,rt<<1
  21. #define rson m+1,r,rt<<1|1
  22. int tag[N<<2],flag[N<<2],now;
  23. void pushup(int rt){
  24. if(flag[rt<<1]==now || flag[rt<<1|1]==now)
  25. flag[rt]=now;
  26. if(tag[rt<<1]==now && tag[rt<<1|1]==now)
  27. tag[rt]=now;
  28. }
  29. void update(int L,int R,ll v,int l,int r,int rt){
  30. if(R<L)return;
  31. if(tag[rt]==now)return;//这个区间不用更新了0
  32. if(L<=l && R>=r && flag[rt]!=now){
  33. ans[l]+=v;ans[r+1]-=v;
  34. flag[rt]=tag[rt]=now;
  35. return;
  36. }
  37. int m=l+r>>1;
  38. if(L<=m)update(L,R,v,lson);
  39. if(R>m)update(L,R,v,rson);
  40. pushup(rt);
  41. }
  42. int main(){
  43. cin>>n>>w;
  44. for(int i=1;i<=n;i++){
  45. int k;cin>>k;
  46. for(int j=1;j<=k;j++){
  47. Node t;
  48. scanf("%lld",&t.a);
  49. t.pos=j;
  50. v[i].push_back(t);
  51. }
  52. }
  53. for(int i=1;i<=n;i++){
  54. now=i;
  55. sort(v[i].begin(),v[i].end(),cmp);
  56. for(int j=0;j<v[i].size();j++){
  57. Node c=v[i][j];
  58. if(c.a<0){
  59. //开头结尾更新进0
  60. update(1,w-v[i].size(),0,1,w,1);
  61. update(v[i].size()+1,w,0,1,w,1);
  62. }
  63. update(c.pos,w-v[i].size()+c.pos,c.a,1,w,1);
  64. }
  65. }
  66. for(int i=1;i<=w;i++)ans[i]+=ans[i-1];
  67. for(int i=1;i<=w;i++)cout<<ans[i]<<" ";
  68. }

转载于:https://www.cnblogs.com/zsben991126/p/11511179.html

发表评论

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

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

相关阅读