双重有序

最近写了挺多双重有序的题目,所以把题目和代码发上来,就当模板参考吧。


正相关

hdu 4719 Oh My Holy FFF


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll maxn = 100010;

struct Node
{
    ll p,v,d;
    Node(ll p=0,ll v=0,ll d=0):p(p),v(v),d(d){}
    bool operator < (const Node& rhs) const
    {
        if(v!=rhs.v) return v<rhs.v;
        else if(d!=rhs.d) return d<rhs.d;
        else return p<rhs.p;
    }
};

ll N,L;
ll a[maxn];
ll ok[maxn];
Node q[maxn];
ll l;

void solve()
{
    scanf("%lld %lld",&N,&L);
    for(ll i=1;i<=N;i++) scanf("%lld",a+i);
    set<Node>s;
    l=1;
    for(ll i=1;i<=N;i++)
    {
        while(i-l>L)
        {
            if(s.count(q[l])) s.erase(q[l]);
            l++;
        }
        set<Node>::iterator it=s.upper_bound(Node(i-L,a[i],0));
        if(s.size()==0||it==s.begin())
        {
            q[i]=Node();
            if(i>L) ok[i]=0;
            else
            {
                q[i]=Node(i,a[i],a[i]*a[i]);
                s.insert(q[i]);
                ok[i]=1;
            }
            continue;
        }
        else
        {
            --it;
            Node now=Node(i,a[i],it->d+a[i]*a[i]-it->v);
            it=s.upper_bound(now);
            if(it!=s.begin()&&(--it)->d>=now.d) continue;
            it=s.upper_bound(now);
            while(it!=s.end()&&it->d<=now.d) s.erase(it++);
            s.insert(now);
            q[i]=now;
            ok[i]=1;
        }
    }
    if(ok[N]) printf("%lld\n",q[N].d);
    else puts("No solution");
}

int main()
{
    ll T;
    scanf("%lld",&T);
    for(ll t=1;t<=T;t++)
    {
        printf("Case #%lld: ",t);
        solve();
    }
    return 0;
}

负相关

hdu 4721 Food and Productivity


代码

#include<bits/stdc++.h>
#define f(i,j) for(int i=1;i<=j;i++)
using namespace std;
const int maxn = 510;
typedef pair<int,int> pii;

int N,M,R,Q,A,B;
int f[maxn][maxn];
int p[maxn][maxn];
int sf[maxn][maxn];
int sp[maxn][maxn];
int af[maxn][maxn];
int ap[maxn][maxn];
pii sb[maxn];
int SB[maxn];
int l;
set<pii>s;

inline int askf(int i,int j)
{
    return sf[min(N,i+R)][min(M,j+R)]-sf[max(0,i-R-1)][min(M,j+R)]-sf[min(N,i+R)][max(0,j-R-1)]+sf[max(0,i-R-1)][max(0,j-R-1)];
}

inline int askp(int i,int j)
{
    return sp[min(N,i+R)][min(M,j+R)]-sp[max(0,i-R-1)][min(M,j+R)]-sp[min(N,i+R)][max(0,j-R-1)]+sp[max(0,i-R-1)][max(0,j-R-1)];
}

void insert(pii x)
{
    if(s.empty())
    {
        s.insert(x);
        return;
    }
    else
    {
        set<pii>::iterator it=s.upper_bound(x);
        if(it!=s.end()&&it->second>=x.second) return;
        if(it==s.begin())
        {
            s.insert(x);
            return;
        }
        --it;
        while(1)
        {
            bool f=(it==s.begin());
            if(it->second<=x.second)
            {
                if(f)
                {
                    s.erase(it);
                    break;
                }
                else s.erase(it--);
            }
            else break;
        }
        s.insert(x);
    }
}

void solve()
{
    s.clear();
    scanf("%d %d %d %d",&N,&M,&R,&Q);
    f(i,N) f(j,M) scanf("%d",&f[i][j]);
    f(i,N) f(j,M) scanf("%d",&p[i][j]);
    f(i,N) f(j,M) sf[i][j]=sf[i-1][j]+sf[i][j-1]+f[i][j]-sf[i-1][j-1];
    f(i,N) f(j,M) sp[i][j]=sp[i-1][j]+sp[i][j-1]+p[i][j]-sp[i-1][j-1];
    f(i,N) f(j,M) af[i][j]=askf(i,j);
    f(i,N) f(j,M) ap[i][j]=askp(i,j);
    f(i,N) f(j,M) insert(make_pair(af[i][j],ap[i][j]));
    l=0;
    for(set<pii>::iterator it=s.begin();it!=s.end();++it)
    {
        sb[l]=*it;
        SB[l]=sb[l].first-sb[l].second;
        l++;
    }
    while(Q--)
    {
        scanf("%d %d",&A,&B);
        int k=lower_bound(SB,SB+l,B-A)-SB;
        int ans=0;
        if(k<l) ans=max(ans,min(sb[k].first+A,sb[k].second+B));
        if(k) ans=max(ans,min(sb[k-1].first+A,sb[k-1].second+B));
        printf("%d\n",ans);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    f(t,T)
    {
        printf("Case #%d:\n",t);
        solve();
        if(t<T) puts("");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值