线段树双tag+差分数组——cf1208E
写了一上午
/* 对于每个数组a[],先排序然后从大到小把a[i]放进线段树更新 设a[i]的位置是pos,那么其可更新的区间是[pos,w-(li-pos)] 线段树结点保存 tag=now表示当前区间已经被更新满了,无需再往下更新 flag=now表示当前区间被更新过 flag=now-1表示当前区间从未被更新过,可以直接进行覆盖 */ #include<bits/stdc++.h> #include<vector> using namespace std; #define N 1000005 #define ll long long ll ans[N]; ll n,w; struct Node{ll pos,a;}; int cmp(Node a,Node b){return a.a>b.a;} vector<Node>v[N]; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int tag[N<<2],flag[N<<2],now; void pushup(int rt){ if(flag[rt<<1]==now || flag[rt<<1|1]==now) flag[rt]=now; if(tag[rt<<1]==now && tag[rt<<1|1]==now) tag[rt]=now; } void update(int L,int R,ll v,int l,int r,int rt){ if(R<L)return; if(tag[rt]==now)return;//这个区间不用更新了0 if(L<=l && R>=r && flag[rt]!=now){ ans[l]+=v;ans[r+1]-=v; flag[rt]=tag[rt]=now; return; } int m=l+r>>1; if(L<=m)update(L,R,v,lson); if(R>m)update(L,R,v,rson); pushup(rt); } int main(){ cin>>n>>w; for(int i=1;i<=n;i++){ int k;cin>>k; for(int j=1;j<=k;j++){ Node t; scanf("%lld",&t.a); t.pos=j; v[i].push_back(t); } } for(int i=1;i<=n;i++){ now=i; sort(v[i].begin(),v[i].end(),cmp); for(int j=0;j<v[i].size();j++){ Node c=v[i][j]; if(c.a<0){//开头结尾更新进0 update(1,w-v[i].size(),0,1,w,1); update(v[i].size()+1,w,0,1,w,1); } update(c.pos,w-v[i].size()+c.pos,c.a,1,w,1); } } for(int i=1;i<=w;i++)ans[i]+=ans[i-1]; for(int i=1;i<=w;i++)cout<<ans[i]<<" "; }