线段树双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]<<" ";
}
转载于//www.cnblogs.com/zsben991126/p/11511179.html
还没有评论,来说两句吧...