BZOJ2482: [Spoj1557] Can you answer these queries II
2015-01-02 20:35
405 查看
题解:
从没见过这么XXX的线段树啊。。。
T_T
我们考虑离线做,按1-n一个一个插入,并且维护区间【 j,i】(i为当前插入的数)j<i的最优值。
但这个最优值!!!
我们要保存历史的最优值,以及当前的最优值!!!还有lazy!!!也得分历史和现在!!T_T
怎么搞!!!
就是这么鬼畜,然后剩下的套模板就好了。。。
其实也蛮好理解的。
tag[0]表示从上次pushdown到现在加了多少
tag[1]表示从上次pushdown到现在tag[0]最多达到过多少,因为祖先的操作可能累计了很多次,我们只需要向下传一下最大的。
mx[0]和mx[1]与tag类似。
对拍了一组数据发现RE了,调了1h发现我dtmk写错了!!!说多了都是泪啊T_T
不过#2还是蛮开心的 哈哈~
代码:
View Code
Submit: 115 Solved: 67
[Submit][Status]
给出m个询问:求l[i]~r[i]的最大子段和(可选空子段)。
这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次。
比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6。
第二行n个数,为给定的序列,这些数的绝对值小于等于100000。
第三行一个数m。
接下来m行,每行两个数,l[i],r[i]。
4 -2 -2 3 -1 -4 2 2 -6
3
1 2
1 5
4 9
5
3
30%:1 <= n, m <= 100
100%:1 <= n, m <= 100000
从没见过这么XXX的线段树啊。。。
T_T
我们考虑离线做,按1-n一个一个插入,并且维护区间【 j,i】(i为当前插入的数)j<i的最优值。
但这个最优值!!!
我们要保存历史的最优值,以及当前的最优值!!!还有lazy!!!也得分历史和现在!!T_T
怎么搞!!!
inline void update(int k,int z1,int z2) { t[k].tag[1]=max(t[k].tag[1],t[k].tag[0]+z2); t[k].tag[0]+=z1; t[k].mx[1]=max(t[k].mx[1],t[k].mx[0]+z2); t[k].mx[0]+=z1; t[k].mx[1]=max(t[k].mx[1],t[k].mx[0]); } inline void pushdown(int k) { if(!t[k].tag[0]&&!t[k].tag[1])return; update(k<<1,t[k].tag[0],t[k].tag[1]); update(k<<1|1,t[k].tag[0],t[k].tag[1]); t[k].tag[0]=t[k].tag[1]=0; }
就是这么鬼畜,然后剩下的套模板就好了。。。
其实也蛮好理解的。
tag[0]表示从上次pushdown到现在加了多少
tag[1]表示从上次pushdown到现在tag[0]最多达到过多少,因为祖先的操作可能累计了很多次,我们只需要向下传一下最大的。
mx[0]和mx[1]与tag类似。
对拍了一组数据发现RE了,调了1h发现我dtmk写错了!!!说多了都是泪啊T_T
不过#2还是蛮开心的 哈哈~
代码:
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<set> #include<queue> #include<string> #define inf 1000000000 #define maxn 200000+5 #define maxm 100000+5 #define eps 1e-10 #define ll long long #define pa pair<int,int> #define for0(i,n) for(int i=0;i<=(n);i++) #define for1(i,n) for(int i=1;i<=(n);i++) #define for2(i,x,y) for(int i=(x);i<=(y);i++) #define for3(i,x,y) for(int i=(x);i>=(y);i--) #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) #define mod 1000000007 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} return x*f; } int n,m,v[maxn],last[maxn],ans[maxn]; struct rec{int l,r,id;}a[maxn]; inline bool cmp(rec x,rec y){return x.r<y.r;} struct seg{int l,r,mx[2],tag[2];}t[4*maxn]; inline void build(int k,int l,int r) { t[k].l=l;t[k].r=r;int mid=(l+r)>>1; if(l==r)return; build(k<<1,l,mid);build(k<<1|1,mid+1,r); } inline void update(int k,int z1,int z2) { t[k].tag[1]=max(t[k].tag[1],t[k].tag[0]+z2); t[k].tag[0]+=z1; t[k].mx[1]=max(t[k].mx[1],t[k].mx[0]+z2); t[k].mx[0]+=z1; t[k].mx[1]=max(t[k].mx[1],t[k].mx[0]); } inline void pushup(int k) { for0(i,1)t[k].mx[i]=max(t[k<<1].mx[i],t[k<<1|1].mx[i]); } inline void pushdown(int k) { if(!t[k].tag[0]&&!t[k].tag[1])return; update(k<<1,t[k].tag[0],t[k].tag[1]); update(k<<1|1,t[k].tag[0],t[k].tag[1]); t[k].tag[0]=t[k].tag[1]=0; } inline void add(int k,int x,int y,int z) { int l=t[k].l,r=t[k].r,mid=(l+r)>>1; if(l==x&&r==y){update(k,z,0);return;} pushdown(k); if(y<=mid)add(k<<1,x,y,z); else if(x>mid)add(k<<1|1,x,y,z); else add(k<<1,x,mid,z),add(k<<1|1,mid+1,y,z); pushup(k); } inline int query(int k,int x,int y) { int l=t[k].l,r=t[k].r,mid=(l+r)>>1; if(l==x&&r==y)return t[k].mx[1]; pushdown(k); if(y<=mid)return query(k<<1,x,y); else if(x>mid)return query(k<<1|1,x,y); else return max(query(k<<1,x,mid),query(k<<1|1,mid+1,y)); } #define last(i) last[100000+i] int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); n=read(); for1(i,n)v[i]=read(); build(1,1,n); m=read(); for1(i,m)a[i].l=read(),a[i].r=read(),a[i].id=i; sort(a+1,a+m+1,cmp); int j=1; for1(i,n) { int tmp=last(v[i]);last(v[i])=i; add(1,tmp+1,i,v[i]); while(a[j].r==i)ans[a[j].id]=query(1,a[j].l,i),j++; } for1(i,m)printf("%d\n",ans[i]); return 0; }
View Code
2482: [Spoj1557] Can you answer these queries II
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 115 Solved: 67
[Submit][Status]
Description
给定n个元素的序列。给出m个询问:求l[i]~r[i]的最大子段和(可选空子段)。
这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次。
比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6。
Input
第一行一个数n。第二行n个数,为给定的序列,这些数的绝对值小于等于100000。
第三行一个数m。
接下来m行,每行两个数,l[i],r[i]。
Output
M行,每行一个数,为每个询问的答案。Sample Input
94 -2 -2 3 -1 -4 2 2 -6
3
1 2
1 5
4 9
Sample Output
45
3
HINT
【数据说明】30%:1 <= n, m <= 100
100%:1 <= n, m <= 100000
Source
spoj gss2相关文章推荐
- bzoj 2482: [Spoj1557] Can you answer these queries II
- bzoj2482 [Spoj1557] Can you answer these queries II
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
- BZOJ 2482 || SPOJ GSS2 Can you answer these queries II(线段树 离线 后缀和)
- bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树
- spoj 1557. Can you answer these queries II(线段树)
- SPOJ 1557 Can you answer these queries II(GSS2 线段树)
- Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字
- SPOJ 1557. Can you answer these queries II 线段树
- SPOJ 1557. Can you answer these queries II (很强的线段树)
- 【SPOJ】1557 Can you answer these queries II 线段树
- 【SPOJ】1557 Can you answer these queries II
- SPOJ 1557 Can you answer these queries II(线段树)
- SPOJ 1557 Can you answer these queries II(离线处理+线段树求历史最大)
- Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字
- [SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]
- spoj 1557 Can you answer these queries II (gss2)线段树
- spojGSS2 1557 Can you answer these queries II(成段更新)
- SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
- SPOJ GSS2 Can you answer these queries II ——线段树