牛客练习赛125 D 扫描线

在这里插入图片描述

思路:

因为颜色的种类范围为1e9,那么肯定不能三重循环dp去得到答案,因为总共也只有1e5数量级的点,所以我们考虑对颜色相同的点进行计算,那么首先我们就要开一个桶,统计每种相同颜色点的各种信息,接下来考虑如何进行计算,我们容易想到,我们可以运用扫描线进行维护,即我们对点的一维进行排序,然后对其中另一维使用数据结构进行维护即可,因为当前点的状态只能由横坐标小于等于自身且纵坐标小于等于自身的点转移过来,所以数据结构我们需要维护另一维的对应信息,因为保证了第一维有序,所以当前点的转化范围即为(1,y),y为自身的纵坐标,从而转化为了查询区间最大值,然后进行单点修改,因此使用线段树进行维护即可。
最后因为要对每种颜色进行维护,所以需要开1e5数量级别的线段树,这里有两种方法,第一种是动态开点,第二种则是只用建一次树,然后每次对使用了节点进行清空即可。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> ar;
const int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"
template<const int T>
struct ModInt {
    const static int mod = T;
    int x;
    ModInt(int x = 0) : x(x % mod) {}
    ModInt(long long x) : x(int(x % mod)) {} 
    int val() { return x; }
    ModInt operator + (const ModInt &a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    ModInt operator - (const ModInt &a) const { int x0 = x - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
    ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
    bool operator == (const ModInt &a) const { return x == a.x; };
    bool operator != (const ModInt &a) const { return x != a.x; };
    void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; }
    void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; }
    void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
    void operator /= (const ModInt &a) { *this = *this / a; }
    friend ModInt operator + (int y, const ModInt &a){ int x0 = y + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    friend ModInt operator - (int y, const ModInt &a){ int x0 = y - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    friend ModInt operator * (int y, const ModInt &a){ return ModInt(1LL * y * a.x % mod);}
    friend ModInt operator / (int y, const ModInt &a){ return ModInt(y) / a;}
    friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
    friend istream &operator>>(istream &is, ModInt &t){return is >> t.x;}

    ModInt pow(int64_t n) const {
        ModInt res(1), mul(x);
        while(n){
            if (n & 1) res *= mul;
            mul *= mul;
            n >>= 1;
        }
        return res;
    }
    
    ModInt inv() const {
        int a = x, b = mod, u = 1, v = 0;
        while (b) {
            int t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        if (u < 0) u += mod;
        return u;
    }
    
};


int tot,rt[200005];
struct node{
    ll sum,lc,rc;
}tree[12000005];
int build(){
    tot++;
    return tot;
}
void pushup(int x){
    tree[x].sum=max(tree[tree[x].lc].sum,tree[tree[x].rc].sum);
    return;
}
void change(int x,int l,int r,int w,ll v){
    if(l==r){
        tree[x].sum=v;
        return;
    }
    int mid=(l+r)/2;
    if(w<=mid){
        if(!tree[x].lc)tree[x].lc=build();
        change(tree[x].lc,l,mid,w,v);
    }
    else{
        if(!tree[x].rc)tree[x].rc=build();
        change(tree[x].rc,mid+1,r,w,v);
    }
    pushup(x);
    return;
}
ll query(int x,int l,int r,int l0,int rr){
    if(r<l0||l>rr)return 0;
    if(l>=l0&&r<=rr){
        return tree[x].sum;
    }
    int mid=(l+r)/2;
    ll res=0;
    res=max(res,query(tree[x].lc,l,mid,l0,rr));
    res=max(res,query(tree[x].rc,mid+1,r,l0,rr));
    return res;
}



void solve()
{
    tot=0;
    int n,m;
    cin>>n>>m;
    map<int,vector<ar> > mp;
    vector<vector<ll> > a(n+5,vector<ll> (m+5)),c(n+5,vector<ll> (m+5));

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) cin>>c[i][j];
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) cin>>a[i][j];
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            mp[c[i][j]].push_back({i,j,a[i][j]});
        }
    }
    ll ans=0;
    int cnt=1;
    for(auto &[x,v]: mp){
        sort(v.begin(),v.end(),[](ar a, ar b)
        {
            if(a[0]==b[0]) return a[1]<b[1];
            return a[0]<b[0];
        });
        rt[cnt]=build();
        for(auto [i,j,val]: v){
            ll res=query(rt[cnt],1,n*m,1,j);
            change(rt[cnt],1,n*m,j,res+val);
        }
        ans=max(ans,query(rt[cnt],1,n*m,1,n*m));
        cnt++;
    }
    cout<<ans<<endl;
    for(int i=0;i<=tot;i++){
        tree[i].lc=tree[i].rc=tree[i].sum=0;
    }
}



int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
	system("pause");
	return 0;
}
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值