去年秋天做的题目,大意是:小镇会连续放n天电影,每天都会放一部编号为x[i]的电影,观看后能获得的对应的值是y[x[i]]。有一个人只能挑连续的几天看电影,并且相同编号的电影他看了超过一遍就会厌倦,这时就会“恢复”成“他没有看过这部电影”的状态(即把这部电影获得的值取消了),如果第一次看就会加上对应的值。问最多能获得多少值?
并且这题无法用树状数组(不能区间更新区间求值)http://opentrains.snarknews.info/~ejudge/team.cgi?SID=5455d7e1154ad0d3&action=2
#include<bits/stdc++.h> #define MAXM 2000010 using namespace std; int a[MAXM]; long long v[MAXM]; long long x[MAXM],y[MAXM]; int n, m; long long ans = 0; vector<int> q[MAXM]; long long sum[MAXM]; int line[MAXM]; struct SegTree //求最值 { struct node { long long num, sum; }tree[MAXM << 2]; int L, R; long long V; void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间) { if (tree[u].num != 0) { node &lson = tree[u << 1], &rson = tree[u << 1 | 1]; lson.num += tree[u].num; rson.num += tree[u].num; tree[u].sum += tree[u].num; tree[u].num = 0; } } void pushUp(int u) //【改】 { tree[u].sum = max(tree[u << 1].sum + tree[u << 1].num, tree[u << 1 | 1].sum + tree[u << 1 | 1].num); } void built(int u, int l, int r) { tree[u].num = 0; if (l == r) { tree[u].sum = 0; return; } int mid = l + r >> 1; built(u << 1, l, mid); built(u << 1 | 1, mid + 1, r); pushUp(u); } void _add(int u, int l, int r)//区间或者点加值 { int mid = l + r >> 1; if (L <= l&&r <= R) { tree[u].num += V; //【改,求和是V*(r-l+1)】 pushDown(u, l, r, mid); return; } pushDown(u, l, r, mid); if (L <= mid) _add(u << 1, l, mid); if (R>mid) _add(u << 1 | 1, mid + 1, r); pushUp(u); } long long _query(int u, int l, int r) { int mid = l + r >> 1; if (L <= l&&r <= R) { pushDown(u, l, r, mid); return tree[u].sum; } pushDown(u, l, r, mid); long long cnt = 0; if (L <= mid) cnt = max(cnt, _query(u << 1, l, mid)); //【改】 if (mid<R) cnt = max(cnt, _query(u << 1 | 1, mid + 1, r)); //【改】 pushUp(u); return cnt; } void add(int l, int r, long long v) { L = l; R = r; V = v; _add(1, 1, n); } long long query(int l, int r) { if (l <= r) { L = l, R = r; return _query(1, 1, n); } else return 0; } }A; int w[1000005]; int fa[1000005]; int main(){ cin>>n>>m; for(int i=1;i<=n;++i){ cin>>x[i]; if (w[x[i]]>=1) fa[i]=w[x[i]]; w[x[i]]=i; } for(int i=1;i<=m;++i) cin>>y[i]; long long maxx=0; for(int i=1;i<=n;++i){ A.add(fa[i]+1,i,y[x[i]]); if(fa[i]!=0) A.add(fa[fa[i]]+1,fa[i],-y[x[i]]); //fa[fa[i]]+1比fa[i]大就会报错 maxx=max(maxx,A.query(1,i)); // update(fa[i],-y[x[i]]); // update(fa[i],-y[x[i]]); // update(fa[fa[i]],y[x[i]]); // 【树状数组要实现区间更新的话,就实现不了区间求和 】 // cout<<"// "<<sum(2)<<" "<<sum(3)<<" "<<sum(4)<<" "<<sum(5)<<" "<<sum(6)<<" "<<sum(7)<<" "<<sum(8)<<" "<<sum(9)<<" "<<sum(10)<<end; } cout<<maxx<<endl; return 0; }
#include<bits/stdc++.h> #define MAXM 2000010 using namespace std; int a[MAXM]; long long v[MAXM]; long long x[MAXM],y[MAXM]; int n, m; long long ans = 0; vector<int> q[MAXM]; long long sum[MAXM]; int line[MAXM]; struct SegTree //求区间和 { struct node { long long num, sum; }tree[MAXM << 2]; int L, R; long long V; void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间) { if (tree[u].num != 0) { node &lson = tree[u << 1], &rson = tree[u << 1 | 1]; lson.num += tree[u].num; rson.num += tree[u].num; tree[u].sum += tree[u].num; tree[u].num = 0; } } void pushUp(int u) //【改】 { tree[u].sum = tree[u << 1].sum + tree[u << 1].num + tree[u << 1 | 1].sum + tree[u << 1 | 1].num; } void built(int u, int l, int r) { tree[u].num = 0; if (l == r) { tree[u].sum = 0; return; } int mid = l + r >> 1; built(u << 1, l, mid); built(u << 1 | 1, mid + 1, r); pushUp(u); } void _add(int u, int l, int r)//区间或者点加值 { int mid = l + r >> 1; if (L <= l&&r <= R) { tree[u].num += V*(r-l+1); //【改,求最值是V】 pushDown(u, l, r, mid); return; } pushDown(u, l, r, mid); if (L <= mid) _add(u << 1, l, mid); if (R>mid) _add(u << 1 | 1, mid + 1, r); pushUp(u); } long long _query(int u, int l, int r) { int mid = l + r >> 1; if (L <= l&&r <= R) { pushDown(u, l, r, mid); return tree[u].sum; } pushDown(u, l, r, mid); long long cnt = 0; if (L <= mid) cnt += _query(u << 1, l, mid); //【改】 if (mid<R) cnt += _query(u << 1 | 1, mid + 1, r); //【改】 pushUp(u); return cnt; } void add(int l, int r, long long v) { L = l; R = r; V = v; _add(1, 1, n); } long long query(int l, int r) { if (l <= r) { L = l, R = r; return _query(1, 1, n); } else return 0; } }A; int main(){ cin>>n>>m; for(int i=1;i<=n;++i){ cin>>x[i]; A.add(i,i,x[i]); } for(int i=1;i<=n;++i){ for(int j=i;j<=n;++j){ cout<<i<<" "<<j<<" "<<A.query(i,j)<<endl; } } return 0; } /* 改编题目,求各区间和 9 4 2 3 1 1 4 1 2 4 1 */
CF380C(div.1)线段树高级推理题
//题目大意:给出一串括号,然后m次询问,问说a,b之间有多少个括号匹配。 //解题思路:首先遍历一遍,将每个位置的从1到当前位置的有效右括号数和没有用到的左括号数记录下来; //然后每次查询a,b区间,即为t = r[b] - r[a-1](有效右括号数), //但是要注意,这些有效右括号的匹配左括号可能不在区间上,所以要减去l[a-1](未用到的左括号数), //但是又有可能[1,a-1]中未用到的左括号和[b+1,len]中的右括号相匹配,所以要加上min(l[a~b]),用到线段树查询最小值。 #include<bits/stdc++.h> #define MAXM 2000010 using namespace std; int a[MAXM]; long long v[MAXM]; long long x[MAXM],y[MAXM]; int n, m; long long ans = 0; vector<int> q[MAXM]; long long sum[MAXM]; int line[MAXM]; struct SegTree //求最值 { struct node { long long num, sum; }tree[MAXM << 2]; int L, R; long long V; void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间) { if (tree[u].num != 0) { node &lson = tree[u << 1], &rson = tree[u << 1 | 1]; lson.num += tree[u].num; rson.num += tree[u].num; tree[u].sum += tree[u].num; tree[u].num = 0; } } void pushUp(int u) //【改】 { tree[u].sum = min(tree[u << 1].sum + tree[u << 1].num, tree[u << 1 | 1].sum + tree[u << 1 | 1].num); } void built(int u, int l, int r) { tree[u].num = 0; if (l == r) { tree[u].sum = 0; return; } int mid = l + r >> 1; built(u << 1, l, mid); built(u << 1 | 1, mid + 1, r); pushUp(u); } void _add(int u, int l, int r)//区间或者点加值 { int mid = l + r >> 1; if (L <= l&&r <= R) { tree[u].num += V; //【改,求和是V*(r-l+1)】 pushDown(u, l, r, mid); return; } pushDown(u, l, r, mid); if (L <= mid) _add(u << 1, l, mid); if (R>mid) _add(u << 1 | 1, mid + 1, r); pushUp(u); } long long _query(int u, int l, int r) { int mid = l + r >> 1; if (L <= l&&r <= R) { pushDown(u, l, r, mid); return tree[u].sum; } pushDown(u, l, r, mid); long long cnt = 100000000; //注意 if (L <= mid) cnt = min(cnt, _query(u << 1, l, mid)); //【改】 if (mid<R) cnt = min(cnt, _query(u << 1 | 1, mid + 1, r)); //【改】 pushUp(u); return cnt; } void add(int l, int r, long long v) { L = l; R = r; V = v; _add(1, 1, n); } long long query(int l, int r) { if (l <= r) { L = l, R = r; return _query(1, 1, n); } else return 0; } }A; int l[1000005]; int r[1000005]; int main(){ char x[1000005]; scanf("%s",x); n=strlen(x); int a=0,b=0,s=0; for(int i=1;i<=n;++i){ if(x[i-1]=='(') a++; else b++; b=min(a,b); if(a>0&&b>0){ s++; a--; b--; } l[i]=a; r[i]=s; A.add(i,i,a); } int q; scanf("%d",&q); while(q--){ scanf("%d%d",&a,&b); printf("%d\n",((r[b]-r[a-1])-max(l[a-1]-(int)A.query(a,b),0))*2); } return 0; }