bzoj 3747: [POI2015]Kinoman
(颓废扒题解2333)
给颜色的下一个出现位置记录一下,然后每次只有第一个颜色的出现位置和下一个出现位置之间会产生这种颜色的价值,所以用线段树维护一下区间。
那么现在就只需要把整个的数列从1->n搞一下,然后移动左端点,每次都更新答案就好,每一次移动,当前位置和下一个出现本颜色的出现位置减去,下一个和下下个加上就好,(没下下个就n呗2333,,,都一样)
1 #include<bits/stdc++.h> 2 #define N 100005 3 #define M 10000005 4 #define LL long long 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 inline int ra() 8 { 9 int x=0,f=1; char ch=getchar(); 10 while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} 11 while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} 12 return x*f; 13 } 14 int n,m;int f[1000005],w[1000005]; 15 int last[1000005],next[1000005]; 16 LL ans; 17 struct seg{ 18 int l,r; 19 LL tag,mx; 20 }t[4000005]; 21 void pushdown(int k) 22 { 23 int l=t[k].l,r=t[k].r; 24 if (l==r) return; 25 LL tag=t[k].tag; t[k].tag=0; 26 t[k<<1].tag+=tag; t[k<<1|1].tag+=tag; 27 t[k<<1].mx+=tag; t[k<<1|1].mx+=tag; 28 } 29 void build(int k, int l, int r) 30 { 31 t[k].l=l; t[k].r=r; 32 if (l==r) return; 33 int mid=l+r>>1; 34 build(k<<1,l,mid); build(k<<1|1,mid+1,r); 35 } 36 void add(int k, int x, int y, int val) 37 { 38 if (t[k].tag) pushdown(k); 39 int l=t[k].l,r=t[k].r; 40 if (l==x && y==r) 41 { 42 t[k].tag+=val; t[k].mx+=val; 43 return; 44 } 45 int mid=l+r>>1; 46 if (y<=mid) add(k<<1,x,y,val); 47 else if (x>mid) add(k<<1|1,x,y,val); 48 else add(k<<1,x,mid,val),add(k<<1|1,mid+1,y,val); 49 t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx); 50 } 51 int main() 52 { 53 n=ra(); m=ra(); 54 for (int i=1; i<=n; i++) f[i]=ra(); 55 for (int i=1; i<=m; i++) w[i]=ra(); 56 for (int i=n; i>=1; i--) next[i]=last[f[i]],last[f[i]]=i; 57 build(1,1,n); 58 for (int i=1; i<=m; i++) 59 if (last[i]) 60 { 61 if (!next[last[i]]) add(1,last[i],n,w[i]); 62 else add(1,last[i],next[last[i]]-1,w[i]); 63 } 64 for (int i=1; i<=n; i++) 65 { 66 ans=max(ans,t[1].mx); 67 int t=next[i]; 68 if (t) 69 { 70 add(1,i,t-1,-w[f[i]]); 71 if (next[t]) add(1,t,next[t]-1,w[f[i]]); 72 else add(1,t,n,w[f[i]]); 73 } 74 else add(1,i,n,-w[f[i]]); 75 } 76 cout<<ans; 77 return 0; 78 }