题目大意
你有$n$个物品,第$i$-th个物品价值为$a_i$,商人有$m$个物品,第$i$-th个物品价值为$b_i$,你可以将自己的某个物品,假设价值为$a_i$,与商人手中价值不超过$a_i+k$的物品交换。现在有$q$次询问,每次给定一个$k$值,求能通过以上操作能使手中物品价值之和到达的最大值。
解题思路
将物品价值从大到小排序后进行合并。相邻插值小于$k$即可进行合并。同时拿并查集维护可选数。可以对需要查询的$k$进行排序,减小复杂度。具体实现看代码。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <bits/stdc++.h> #define maxn 400100 #define int long long typedef __int128_t int128; using namespace std; const double eps=1e-8; int f[maxn]; int sz[maxn],sum[maxn]; pair<int,int>a[maxn],que[maxn]; map<int,vector<int>>num; int ans[maxn]; int find(int x){ if(f[x]!=x) f[x]=find(f[x]); return f[x]; } void solve(){ int n,m,q,res=0; cin >> n >> m >> q; for(int i=1;i<=n+m;++i) cin >> a[i].first,a[i].second=i; sort(a+1,a+n+m+1); for(int i=1;i<=n+m;++i){ if(a[i].second<=n) res+=a[i].first; sz[i]=(a[i].second<=n); f[i]=i; sum[i]=sum[i-1]+a[i].first; if(i>1) num[a[i].first-a[i-1].first].push_back(i-1); } for(int i=1;i<=q;++i) cin >> que[i].first,que[i].second=i; sort(que+1,que+q+1); auto it=num.begin(); for(int i=1;i<=q;++i){ if(que[i].first==que[i-1].first) {ans[que[i].second]=res;continue;} while(it!=num.end()&&it->first<=que[i].first){ for(auto u:it->second){ int a=find(u),b=find(u+1); res-=sum[a]-sum[a-sz[a]]+sum[b]-sum[b-sz[b]]; f[a]=b; sz[b]+=sz[a]; res+=sum[b]-sum[b-sz[b]]; } ++it; } ans[que[i].second]=res; } for(int i=1;i<=q;++i) cout << ans[i] << '\n'; } signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t=1; while(t--){ solve(); } return 0; }
|