您的位置:首页 > 其它

连续看几天电影 最多能获得的值【线段树模板】

2016-01-24 18:14 465 查看




去年秋天做的题目,大意是:小镇会连续放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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: