P3527 [POI2011]MET-Meteors
P3527 [POI2011]MET-Meteors
题意
给定一段1-m
的区间,n
个国家,每个位置属于一个国家
每个国家有目标的权值
有k次操作,对于每次操作
- 当
l<=r
l-r
区间内的位置上的权值+v
- 当
l>r
l-m,1-r
区间内的位置上的权值+v
- 问最少几次操作,后国家所有地区的权值和达到目标
达不到输出NIE
\(1\le n,m,k\le 3\cdot10^5\)
\(1\le p_i,a_i\le 10^9\)
正文
直接主席树动态记录每次操作后的区间的状态
对于每个国家单独二分最小操作次数
时间复杂度\(o(nlognlogn)\)
ps:不做处理n*m*v
爆ll
题目空间限制60MB
的话就MLE 主席树不优化空间要开n*logn*4
考虑整体二分
类似与cdq分治的思想
将时间 修改和查询一起分治
直接用树状数组维护修改操作
时间复杂度\(o(nlognlogn)\)
将区间修改操作拆分为左右端点,左加右减
通过前缀和&修改位置判定统计
初始按修改位置排序,分治过程中维护区间内位置有序(同cdq分治维护内部有序)
按每个位置单独计算贡献,按国家是否达到目标 区分该分到左或右区间
时间复杂度\(o(nlogn)\)
主席树code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
ll s=0,r=1;
char c=C;
for(;c<0||c>9;c=C) if(c==-3) r=-1;
for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
return s*r;
}
#define pb push_back
const int N=3e5+10,inf=1e9+7;
int n,m,k,top,tmpv;
ll a[N];
int rt[N];
vector<int>b[N];
struct xin{
int l,r;
ll sum;
}tr[N*55];
inline void build(int &x,int l,int r)
{
x=++top;
if(l==r) return;
int mid=(l+r)>>1;
build(tr[x].l,l,mid);build(tr[x].r,mid+1,r);
}
inline int add(int x,int l,int r,int ql,int qr,int qv)
{
int xx=++top;tr[xx]=tr[x];
if(ql<=l&&r<=qr)
{
tr[xx].sum+=qv;
if(tr[xx].sum>=inf) tr[xx].sum=inf;
return xx;
}
int mid=(l+r)>>1;
if(ql<=mid) tr[xx].l=add(tr[x].l,l,mid,ql,qr,qv);
if(mid+1<=qr) tr[xx].r=add(tr[x].r,mid+1,r,ql,qr,qv);
return xx;
}
inline void ask(int x,int l,int r,int qw)
{
tmpv+=tr[x].sum;
if(tmpv>=inf) tmpv=inf;
if(l==r) return;
int mid=(l+r)>>1;
if(qw<=mid) ask(tr[x].l,l,mid,qw);
if(mid+1<=qw) ask(tr[x].r,mid+1,r,qw);
}
inline int pd(int w,int wk)
{
tmpv=0;
for(int i=0,edi=b[w].size();i<edi;i++)
{
int u=b[w][i];
ask(rt[wk],1,m,u);
}
return tmpv>=a[w];
}
inline void two(int w)
{
int l=1,r=k;
while(l<r)
{
int mid=(l+r)>>1;
if(pd(w,mid)) r=mid;
else l=mid+1;
}
if(pd(w,r)) printf("%d\n",r);
else puts("NIE");
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++) b[read()].pb(i);
for(int i=1;i<=n;i++) a[i]=read();
k=read();build(rt[0],1,m);
for(int i=1;i<=k;i++)
{
int l=read(),r=read(),v=read();
if(l<=r)
{
rt[i]=add(rt[i-1],1,m,l,r,v);
}
if(l>r)
{
int tmprt=add(rt[i-1],1,m,l,m,v);
rt[i]=add(tmprt,1,m,1,r,v);
}
}
for(int i=1;i<=n;i++) two(i);
return 0;
}
整体二分拆分区间code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
ll s=0,r=1;
char c=C;
for(;c<0||c>9;c=C) if(c==-3) r=-1;
for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
return s*r;
}
const int N=3e5+10,inf=1e9+7;
int n,m,k,topq;
int g[N],a[N],akw[N],ans[N];
int tmpakw[N];
ll sum[N],re[N];
struct xin{
int w,t,v;
friend bool operator<(const xin &a,const xin &b)
{
return a.w<b.w;
}
}q[N<<2],tmpq[N<<2];
inline void cdq(int tl,int tr,int akl,int akr,int ql,int qr)
{
if(tl==tr)
{
for(int i=akl;i<=akr;i++) ans[g[akw[i]]]=tl;
return;
}
int midt=(tl+tr)>>1;
int tmpql=ql,tmpqr=qr;
copy(q+ql,q+1+qr,tmpq+ql);
for(int i=ql;i<=qr;i++)
{
if(tmpq[i].t<=midt) q[tmpql++]=tmpq[i];
else q[tmpqr--]=tmpq[i];
}
reverse(q+tmpqr+1,q+1+qr);
int tmpakl=akl,tmpakr=akr;
copy(akw+akl,akw+1+akr,tmpakw+akl);
for(int i=akl;i<=akr;i++)
{
int u=g[tmpakw[i]];
re[u]=sum[u];
}
ll tmpsum=0;
for(int i=akl,j=ql;i<=akr;i++)
{
int w=tmpakw[i];int u=g[w];
while(j<=tmpqr&&q[j].w<=w)
{
tmpsum+=q[j].v;
j++;
}
sum[u]+=tmpsum;
if(sum[u]>=inf) sum[u]=inf;
}
for(int i=akl;i<=akr;i++)
{
int w=tmpakw[i];int u=g[w];
if(sum[u]>=a[u])
{
akw[tmpakl++]=w;
}
else
{
akw[tmpakr--]=w;
re[u]=-1;
}
}
for(int i=akl;i<=akr;i++)
{
int w=tmpakw[i];int u=g[w];
if(re[u]!=-1) sum[u]=re[u];
}
reverse(akw+tmpakr+1,akw+1+akr);
cdq(tl,midt,akl,tmpakr,ql,tmpqr);
cdq(midt+1,tr,tmpakr+1,akr,tmpqr+1,qr);
}
int main()
{
n=read(),m=read();
for(int i=0;i<=m;i++) akw[i]=i;
for(int i=1;i<=m;i++) g[i]=read();
for(int i=1;i<=n;i++) a[i]=read();
k=read();
for(int i=1;i<=n;i++) ans[i]=k+1;
for(int i=1;i<=k;i++)
{
int l=read(),r=read(),v=read();
if(l<=r)
{
q[++topq]=(xin){l,i,v};
q[++topq]=(xin){r+1,i,-v};
}
else
{
q[++topq]=(xin){l,i,v};
q[++topq]=(xin){m+1,i,-v};
q[++topq]=(xin){1,i,v};
q[++topq]=(xin){r+1,i,-v};
}
}
sort(q+1,q+1+topq);
cdq(0,k+1,1,m,1,topq);
for(int i=1;i<=n;i++)
{
if(ans[i]==k+1) puts("NIE");
else printf("%d\n",ans[i]);
}
return 0;
}