题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值
首先我们考虑暴力想法
对于每个国家分开讨论 二分操作次数
但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大
这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE
我们需要对浪费在这里的复杂度做一些改进
1.可持久化线段树(MLE)
每次二分一个mid之后 我们要找到mid次操作之后的版本
那么很容易想到可持久化线段树
这样每次二分到一个mid可以O(logm)得到值 时间复杂度O(klogm+nlogklogm)
残念的是我MLE了- - 本来以为写了标记永久化的线段树能省掉不少空间的- - 结果- -
内存池就算开了1500W也不够用 真是卡成狗- -
2.整体二分
不能从k下手,我们就要从n下手
二分Solve(x,y,S)表示答案落在[x,y]区间内的国家集合为S
将当前的修改调整至mid,将S集合分为两部分:答案落在[l,mid]的S1和[mid+1,r]的S2
对这两部分继续分治 直到x==y为止 统计答案 退出
时间复杂度O(nlogklogm) 此外注意30W*30W*10E会爆long long 所以我开成了double。。。
代码(整体二分):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
struct Segtree{
Segtree *ls,*rs;
double val;
void* operator new (size_t)
{
static Segtree mempool[M<<1],*C=mempool;
return C++;
}
void Build_Tree(int x,int y)
{
int mid=x+y>>1;
if(x==y)
return ;
ls=new Segtree;
rs=new Segtree;
ls->Build_Tree(x,mid);
rs->Build_Tree(mid+1,y);
}
void Modify(int x,int y,int l,int r,int val)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
this->val+=val;
return ;
}
if(r<=mid) ls->Modify(x,mid,l,r,val);
else if(l>mid) rs->Modify(mid+1,y,l,r,val);
else ls->Modify(x,mid,l,mid,val),rs->Modify(mid+1,y,mid+1,r,val);
}
double Get_Ans(int x,int y,int pos)
{
int mid=x+y>>1;
if(x==y)
return val;
if(pos<=mid)
return val+ls->Get_Ans(x,mid,pos);
else
return val+rs->Get_Ans(mid+1,y,pos);
}
}tree;
struct abcd{
int pos,next;
}table[M];
struct modification{
int l,r,p;
}modifications[M];
int head[M],tot;
int n,m,k,now;
int a[M],q[M],ans[M];
void Add(int x,int y)
{
table[++tot].pos=y;
table[tot].next=head[x];
head[x]=tot;
}
void Holistic_Bisection(int x,int y,int l,int r)
{
static int nq[M];
int i,mid=x+y>>1;
if(l>r) return ;
if(x==y)
{
for(i=l;i<=r;i++)
ans[q[i]]=mid;
return ;
}
while(now<mid)
{
++now;
if(modifications[now].l<=modifications[now].r)
tree.Modify(1,m,modifications[now].l,modifications[now].r,modifications[now].p);
else
tree.Modify(1,m,1,modifications[now].r,modifications[now].p),
tree.Modify(1,m,modifications[now].l,m,modifications[now].p);
}
while(now>mid)
{
if(modifications[now].l<=modifications[now].r)
tree.Modify(1,m,modifications[now].l,modifications[now].r,-modifications[now].p);
else
tree.Modify(1,m,1,modifications[now].r,-modifications[now].p),
tree.Modify(1,m,modifications[now].l,m,-modifications[now].p);
--now;
}
int _l=l,_r=r;
for(int j=l;j<=r;j++)
{
double temp=0;
for(i=head[q[j]];i;i=table[i].next)
{
temp+=tree.Get_Ans(1,m,table[i].pos);
if(temp>=1000000000)
temp=1000000000;
}
if(temp>=a[q[j]])
nq[_l++]=q[j];
else nq[_r--]=q[j];
}
memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1) );
Holistic_Bisection(x,mid,l,_l-1);
Holistic_Bisection(mid+1,y,_r+1,r);
}
int main()
{
int i,x;
cin>>n>>m;
for(i=1;i<=m;i++)
{
scanf("%d",&x);
Add(x,i);
}
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
tree.Build_Tree(1,m);
cin>>k;
for(i=1;i<=k;i++)
scanf("%d%d%d",&modifications[i].l,&modifications[i].r,&modifications[i].p);
for(i=1;i<=n;i++)
q[i]=i;
Holistic_Bisection(1,k+1,1,n);
for(i=1;i<=n;i++)
{
if(ans[i]<=k) printf("%d\n",ans[i]);
else puts("NIE");
}
return 0;
}
代码(可持久化线段树):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
typedef long long ll;
struct Segtree{
Segtree *ls,*rs;
int val;
void* operator new (size_t,Segtree *_,Segtree *__,ll ___)
{
static Segtree mempool[17500000],*C=mempool;
C->ls=_;
C->rs=__;
C->val=___;
if(C->val>=1000000000)
C->val=1000000000;
return C++;
}
}*tree[M];
struct abcd{
int pos,next;
}table[M];
int head[M],tot;
int n,m,k,a[M];
Segtree* Modify(Segtree *p,int x,int y,int l,int r,ll val)
{
int mid=x+y>>1;
if(x==l&&y==r)
return new (p->ls,p->rs,p->val+val) Segtree;
if(r<=mid)
return new (Modify(p->ls,x,mid,l,r,val),p->rs,p->val) Segtree;
if(l>mid) return new (p->ls,Modify(p->rs,mid+1,y,l,r,val),p->val) Segtree;
return new (Modify(p->ls,x,mid,l,mid,val),Modify(p->rs,mid+1,y,mid+1,r,val),p->val) Segtree;
}
Segtree* Modify(Segtree *p,int x,int y,int l,int r,ll val,bool)
{
int mid=x+y>>1;
if(l>mid) return new (new(p->ls->ls,p->ls->rs,p->ls->val+val)Segtree,Modify(p->rs,mid+1,y,l,r,val,true),p->val) Segtree;
if(r<=mid) return new (Modify(p->ls,x,mid,l,r,val,true),new(p->rs->ls,p->rs->rs,p->rs->val+val)Segtree,p->val) Segtree;
return new (Modify(p->ls,x,mid,x,l,val),Modify(p->rs,mid+1,y,r,y,val),p->val) Segtree;
}
ll Get_Ans(Segtree *p,int x,int y,int pos)
{
int mid=x+y>>1;
if(p==tree[0]) return 0;
if(x==y) return p->val;
if(pos<=mid) return p->val+Get_Ans(p->ls,x,mid,pos);
else return p->val+Get_Ans(p->rs,mid+1,y,pos);
}
void Initialize()
{
tree[0]=new (0x0,0x0,0) Segtree;
tree[0]->ls=tree[0]->rs=tree[0];
}
void Add(int x,int y)
{
table[++tot].pos=y;
table[tot].next=head[x];
head[x]=tot;
}
int Bisection(int x)
{
int i,l=0,r=k+1;
while(l+1<r)
{
int mid=l+r>>1;
long long now=0;
for(i=head[x];i;i=table[i].next)
now+=Get_Ans(tree[mid],1,m,table[i].pos);
if(now>=a[x])
r=mid;
else
l=mid;
}
long long now=0;
for(i=head[x];i;i=table[i].next)
now+=Get_Ans(tree[l],1,m,table[i].pos);
return now>=a[x]?l:r;
}
int main()
{
int i,x,y,z;
Initialize();
cin>>n>>m;
for(i=1;i<=m;i++)
{
scanf("%d",&x);
Add(x,i);
}
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
cin>>k;
for(i=1;i<=k;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(x<=y) tree[i]=Modify(tree[i-1],1,m,x,y,z);
else tree[i]=Modify(tree[i-1],1,m,y,x,z,true);
}
for(i=1;i<=n;i++)
{
int temp=Bisection(i);
if(temp==k+1) puts("NIE");
else printf("%d\n",temp);
}
return 0;
}