首页 > 代码库 > BZOJ 3747 POI2015 Kinoman 线段树
BZOJ 3747 POI2015 Kinoman 线段树
题目大意:有m个点,每个点有个权值,现在有这m个点组成的长度为n的序列,求一个区间,这个区间内只出现一次的点的权值和最大
想了半天的一道题居然被神犇说成是水题……我也是醉了
枚举左端点 对于每个左端点求右端点 这个用线段树维护最大值
考虑每个数对答案的贡献 记录一个数组next表示这个位置上的点下一次出现的位置 那么这个点贡献的作用范围就是[i,next[i]-1] 如果没有next就是[i,n]
于是我们先把所有第一个出现的数对答案的贡献加入线段树 然后从左到右扫一遍 每次统计完答案之后把i对答案的贡献去除 然后把next[i]对答案的贡献加入线段树
这常数我也是醉了……速度倒数第二啥的 正解一定不是这样的……
此外POI2015是我穿错年代了?
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1001001 using namespace std; struct Segtree{ Segtree *ls,*rs; long long num,mark; void Build_Tree(int x,int y); void Update(int x,int y,int l,int r,long long val); long long Get_Ans(int x,int y,int l,int r); }*root=new Segtree,mempool[M<<1],*C=mempool; int n,m; int a[M],w[M],next[M],last[M]; bool v[M]; long long ans; void Segtree :: Build_Tree(int x,int y) { int mid=x+y>>1; num=0;mark=0; if(x==y) return ; ls=C++;rs=C++; ls->Build_Tree(x,mid); rs->Build_Tree(mid+1,y); } void Segtree :: Update(int x,int y,int l,int r,long long val) { int mid=x+y>>1; if(x==l&&y==r) { num+=val; mark+=val; return ; } if(mark) { ls->num+=mark; rs->num+=mark; ls->mark+=mark; rs->mark+=mark; mark=0; } if(r<=mid) ls->Update(x,mid,l,r,val); else if(l>mid) rs->Update(mid+1,y,l,r,val); else ls->Update(x,mid,l,mid,val),rs->Update(mid+1,y,mid+1,r,val); num=max(ls->num,rs->num); } long long Segtree :: Get_Ans(int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return num; if(mark) { ls->num+=mark; rs->num+=mark; ls->mark+=mark; rs->mark+=mark; mark=0; } if(r<=mid) return ls->Get_Ans(x,mid,l,r); if(l> mid) return rs->Get_Ans(mid+1,y,l,r); return max( ls->Get_Ans(x,mid,l,mid) , rs->Get_Ans(mid+1,y,mid+1,r) ); } int main() { int i; cin>>n>>m; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) scanf("%d",&w[i]); for(i=1;i<=n;i++) { if(last[a[i]]) next[last[a[i]]]=i; else v[i]=1; last[a[i]]=i; } root->Build_Tree(1,n); for(i=1;i<=n;i++) if(v[i]) root->Update(1,n,i,next[i]?next[i]-1:n,w[a[i]]); for(i=1;i<=n;i++) { ans=max(ans, root->Get_Ans(1,n,i,n) ); root->Update(1,n,i,next[i]?next[i]-1:n,-w[a[i]]); if(next[i]) root->Update(1,n,next[i],next[next[i]]?next[next[i]]-1:n,w[a[next[i]]]); } cout<<ans<<endl; }
BZOJ 3747 POI2015 Kinoman 线段树
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。