题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3872
题目思路:单调队列加线段树优化,单调队列的作用是将序列分成最大值不同的若干段。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define Max 100100 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int dp[Max],t,n,typ[Max],val[Max],rec,q[Max],lef[Max]; struct node { int l,r,minx; int mid() { return (l+r)>>1; } }T[4*Max]; void build(int l,int r,int rt) { T[rt].l=l;T[rt].r=r; T[rt].minx=0; if(l==r) { // T[rt].max=val[l]; return ; } int mid=T[rt].mid(); build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void modify(int l,int rt,int data) { if(T[rt].l==T[rt].r) { T[rt].minx=data; return; } int mid=T[rt].mid(); if(l<=mid) modify(l,rt<<1,data); else modify(l,rt<<1|1,data); T[rt].minx=min(T[rt<<1].minx,T[rt<<1|1].minx); } void query(int l,int r,int rt) { if(T[rt].l==l&&T[rt].r==r) { rec=min(rec,T[rt].minx); return; } int mid=T[rt].mid(); if(l>=mid+1) query(l,r,rt<<1|1); else if(r<=mid) query(l,r,rt<<1); else { query(l,mid,rt<<1); query(mid+1,r,rt<<1|1); } } int main() { int i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&typ[i]); } for(i=1;i<=n;i++) { scanf("%d",&val[i]); } dp[0]=0; int top=0;int tail=1; build(0,n,1); q[0]=0; memset(lef,0,sizeof(lef)); for(i=1;i<=n;i++) { // int maxn=val[i]; while(tail>top+1&&val[i]>val[q[tail-1]]) tail--; q[tail]=i; tail++; dp[i]=inf; for(j=tail-1;j>top&&q[j]>lef[typ[i]];j--) { rec=inf; query(max(q[j-1],lef[typ[i]]),q[j]-1,1); // printf("a"); dp[i]=min(rec+val[q[j]],dp[i]); } modify(i,1,dp[i]); lef[typ[i]]=i; // printf("i %d dp %d\n",i,dp[i]); } printf("%d\n",dp[n]); } }