答案显然是具有二分性的,操作是区间加和单点查询,并且每个国家是独立的,我们考虑整体二分。
每次二分一个mid,将[1,mid]的操作区间都加入答案,然后分治。
容易想到用可持久化线段树继续维护[mid+1,r],避免重复的操作。
然而准备写之前看了PoPoQQQ大爷的题解发现会MLE
然后我就瞬间一脸懵逼。。
然后我们考虑树状数组,并设立一个指针,每次都移动到当前的mid处,并把经过的点加入BIT或从BIT中删除,可以发现每一个点最多会被操作3次,复杂度有了保证。
#include<iostream>
#include<cstdio>
#include<vector>
#define lowbit(i) (i&(-i))
#define ll long long
#define inf 1000000007
using namespace std;
int n,m,k,now;
ll tree[300005];
struct node {int x,y,z;} p[300005];
struct date {int id,exp;} b[300005],b1[300005],b2[300005];
int ans[300005];
vector <int> a[300005];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void add(int x,int val)
{
for (int i=x;i<=m;i+=lowbit(i)) tree[i]+=val;
}
inline ll query(int x)
{
ll tmp=0;
for (int i=x;i;i-=lowbit(i)) tmp+=tree[i];
return tmp;
}
inline void change(int x,int f)
{
if (p[x].x<=p[x].y) add(p[x].x,f*p[x].z),add(p[x].y+1,f*(-p[x].z));
else add(1,f*p[x].z),add(p[x].y+1,f*(-p[x].z)),add(p[x].x,f*p[x].z);
}
void solve(int t,int w,int l,int r)
{
if (t>w) return;
if (l==r)
{
for (int i=t;i<=w;i++) ans[b[i].id]=l;
return;
}
int mid=l+r>>1;
while (now<=mid) change(++now,1);
while (now>mid) change(now--,-1);
int p1=0,p2=0;
for (int i=t;i<=w;i++)
{
ll tmp=0;
for (int j=0;j<a[b[i].id].size();j++)
{
tmp+=query(a[b[i].id][j]);
if (tmp>=b[i].exp) break;
}
if (tmp>=b[i].exp) b1[++p1]=b[i]; else b2[++p2]=b[i];
}
for (int i=1;i<=p1;i++) b[t+i-1]=b1[i];
for (int i=1;i<=p2;i++) b[t+i+p1-1]=b2[i];
solve(t,t+p1-1,l,mid); solve(t+p1,w,mid+1,r);
}
int main()
{
n=read(); m=read();
for (int i=1;i<=m;i++) a[read()].push_back(i);
for (int i=1;i<=n;i++) b[i].exp=read(),b[i].id=i;
k=read();
for (int i=1;i<=k;i++)
p[i].x=read(),p[i].y=read(),p[i].z=read();
p[++k].x=1; p[k].y=m; p[k].z=inf;
solve(1,n,1,k);
for (int i=1;i<=n;i++)
ans[i]==k?puts("NIE"):printf("%d\n",ans[i]);
return 0;
}