题目大意:给定一个环,每个节点有一个所属国家,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 所以我开成了short。。。
代码(整体二分):
#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; }
时间: 2024-10-18 09:42:18