bzoj2482

还是像以前那样维护下次出现位置,计算影响

其实不难,思维盲点,受到做最大子段和的影响

其实这里可以直接维护当前每个位置的子段和,再记录一个历史最大和

当然tag也需要记录当前tag和历史(距离上次push)最大累加

  1 type node=record
  2        x,y,id:longint;
  3      end;
  4
  5 var lazy,tree:array[0..100010*4,0..1] of longint;
  6     ans,next,a:array[0..100010] of longint;
  7     last:array[-100010..100010] of longint;
  8     q:array[0..100010] of node;
  9     i,j,n,m:longint;
 10
 11 function max(a,b:longint):longint;
 12   begin
 13     if a>b then exit(a) else exit(b);
 14   end;
 15
 16 procedure swap(var a,b:node);
 17   var c:node;
 18   begin
 19     c:=a;
 20     a:=b;
 21     b:=c;
 22   end;
 23
 24 procedure sort(l,r:longint);
 25   var i,j,x:longint;
 26   begin
 27     i:=l;
 28     j:=r;
 29     x:=q[(l+r) shr 1].x;
 30     repeat
 31       while q[i].x>x do inc(i);
 32       while x>q[j].x do dec(j);
 33       if i<=j then
 34       begin
 35         swap(q[i],q[j]);
 36         inc(i);
 37         dec(j);
 38       end;
 39     until i>j;
 40     if l<j then sort(l,j);
 41     if i<r then sort(i,r);
 42   end;
 43
 44 procedure get(i,x0,x1:longint);
 45   begin
 46     tree[i,0]:=max(tree[i,0],tree[i,1]+max(x0,x1));
 47     lazy[i,0]:=max(lazy[i,0],lazy[i,1]+max(x0,x1));
 48     inc(lazy[i,1],x1);
 49     inc(tree[i,1],x1);
 50   end;
 51
 52 procedure update(i:longint);
 53   begin
 54     tree[i,0]:=max(tree[i*2,0],tree[i*2+1,0]);
 55     tree[i,1]:=max(tree[i*2,1],tree[i*2+1,1]);
 56   end;
 57
 58 procedure push(i:longint);
 59   begin
 60     if (lazy[i,1]=0) and (lazy[i,0]=0) then exit;
 61     get(i*2,lazy[i,0],lazy[i,1]);
 62     get(i*2+1,lazy[i,0],lazy[i,1]);
 63     lazy[i,0]:=0;
 64     lazy[i,1]:=0;
 65   end;
 66
 67 procedure add(i,l,r,x,y,z:longint);
 68   var m:longint;
 69   begin
 70     if (x<=l) and (y>=r) then get(i,0,z)
 71     else begin
 72       m:=(l+r) shr 1;
 73       push(i);
 74       if x<=m then add(i*2,l,m,x,y,z);
 75       if y>m then add(i*2+1,m+1,r,x,y,z);
 76       update(i);
 77     end;
 78   end;
 79
 80 function ask(i,l,r,x:longint):longint;
 81   var m:longint;
 82   begin
 83     if l=r then exit(tree[i,0])
 84     else begin
 85       m:=(l+r) shr 1;
 86       push(i);
 87       if x<=m then exit(ask(i*2,l,m,x))
 88       else exit(max(tree[i*2,0],ask(i*2+1,m+1,r,x)));
 89     end;
 90   end;
 91
 92 begin
 93   readln(n);
 94   for i:=1 to n do
 95     read(a[i]);
 96   for i:=n downto 1 do
 97   begin
 98     next[i]:=last[a[i]];
 99     last[a[i]]:=i;
100   end;
101   readln(m);
102   for i:=1 to m do
103   begin
104     readln(q[i].x,q[i].y);
105     q[i].id:=i;
106   end;
107   sort(1,m);
108   j:=1;
109   for i:=n downto 1 do
110   begin
111     if next[i]=0 then next[i]:=n+1;
112     add(1,1,n,i,next[i]-1,a[i]);
113     while (j<=m) and (q[j].x=i) do
114     begin
115       ans[q[j].id]:=ask(1,1,n,q[j].y);
116       inc(j);
117     end;
118     if j=m+1 then break;
119   end;
120   for i:=1 to m do
121     writeln(ans[i]);
122 end.

时间: 2024-12-31 17:38:19

bzoj2482的相关文章

【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树

[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6. Input 第一行一个数n. 第二行n个数,为给定的序列,这些数的绝对值小于等于100000. 第三行一个数m. 接下来m行,每行两个

BZOJ2482: [Spoj1557] Can you answer these queries II

题解: 从没见过这么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