2024/12/19 总结
Recommendations
给你 n 个区间,对每个区间求所有包含这个区间的区间包含元素的交(不包括被包含的区间本身)
将l设为x轴,r设为y轴,每个点就可以表示为平面直角坐标系上的点。发现一个点的左上所有点被这个点包含,从上往下扫描线,从左往右加点即可。需要离散化,特判区间重合
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define _1 first
#define _2 second
constexpr int maxn = 1e6+10;
constexpr int inf = 1e18;
int n , m , l[maxn] , r[maxn] , a[maxn];
pair <int , int> lst;
vector <pair <int , int> > p[maxn];
int mn[maxn] , mx[maxn] , ans[maxn];
void update1 (int pos , int c){
while (pos <= m){
mn[pos] = min (c , mn[pos]);
pos += pos & (-pos);
}
}
int query1 (int pos){
int ans = inf;
while (pos){
ans = min (ans , mn[pos]);
pos -= pos & (-pos);
}
return ans;
}
void update2 (int pos , int c){
while (pos <= m){
mx[pos] = max (c , mx[pos]);
pos += pos & (-pos);
}
}
int query2 (int pos){
int ans = 0;
while (pos){
ans = max (ans , mx[pos]);
pos -= pos & (-pos);
}
return ans;
}
signed main (){
ios::sync_with_stdio (0);
cin.tie(0),cout.tie(0);
int t;
cin >> t;
while (t --> 0){
m = 0;
cin >> n;
for (int i = 1;i <= n;i ++)
cin >> l[i] >> r[i] , a[++ m] = l[i] , a[++ m] = r[i] , ans[i] = 0;
sort (a + 1 , a + m + 1);
m = unique (a + 1 , a + m + 1) - a - 1;
for (int i = 1;i <= n;i ++){
l[i] = lower_bound (a + 1 , a + m + 1 , l[i]) - a , r[i] = lower_bound (a + 1 , a + m + 1 , r[i]) - a;
p[r[i]].push_back ({l[i] , i});
}
for (int i = 1;i <= m;i ++)
sort (p[i].begin () , p[i].end ()) , mx[i] = 0 , mn[i] = 1e18;
for (int i = m;i >= 1;i --){
lst = {0 , 0};
for (auto j : p[i]){
if (lst._1 == j._1)
ans[lst._2] = 0;
else{
int f = query1 (j._1) , g = query2 (j._1);
if (g >= 1 && f <= m)
ans[j._2] = a[query1 (j._1)] - a[query2 (j._1)];
update1 (j._1 , i) , update2 (j._1 , j._1);
}
lst = j;
}
p[i].clear ();
}
for (int i = 1;i <= n;i ++)
cout << max (0ll , ans[i] - a[r[i]] + a[l[i]]) <<endl;
}
return 0;
}
T-shirts
n种物品,有质量q和价格c。m个顾客,每个顾客每次会选当前能负担起的最大价值物品,价值相同时选最便宜的,选若干次直到没有能选的了。每个物品对每个顾客限购一次。
首先不妨将问题转换一下,直接打暴力的话是对每个顾客枚举物品,显然无法优化。所以变为先将物品按优先级排序,显然从最高优先级的开始枚举,能买得起的顾客都会买,同时买之后将所有买过的顾客答案增加,余额减少。
建一颗平衡树来进行优化,但是我们发现依旧无法避免暴力修改顾客的答案和余额,所以有一个技巧。
我们枚举到一个物品时,将树(用的FHQ,比较好写)分裂成剩余价格为0c,c2c,2c~ 三部分。显然第一部分买不起这个物品,第二部分进去暴力修改,第三部分由于修改之后位置不会变,所以直接打一个答案标记和余额标记就可以了。
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn = 2e5+10;
int n, m;
struct ASK{
int c,q;
bool operator <(const ASK x){
if(q != x.q){
return q > x.q;
}
return c < x.c;
}
}a[maxn];
mt19937 Rand(time(0));
struct note{
int l,r;
int id, val, key;
int cntlz,minlz,cnt;
}s[maxn];
int ncnt = 0;
int root = 0;
void push_down(int k) {
if (s[k].minlz) {
if (s[k].l) s[s[k].l].minlz += s[k].minlz,
s[s[k].l].val -= s[k].minlz;
if (s[k].r) s[s[k].r].minlz += s[k].minlz,
s[s[k].r].val -= s[k].minlz;
s[k].minlz = 0;
}
if (s[k].cntlz) {
if (s[k].l) s[s[k].l].cntlz += s[k].cntlz, s[s[k].l].cnt += s[k].cntlz;
if (s[k].r) s[s[k].r].cntlz += s[k].cntlz, s[s[k].r].cnt += s[k].cntlz;
s[k].cntlz = 0;
}
}
void split(int k,int val,int &x,int &y){
if(!k){
x = y = 0;
return;
}
push_down(k);
if(s[k].val <= val){
x = k;
split(s[k].r,val,s[k].r,y);
}
else{
y = k;
split(s[k].l,val,x,s[k].l);
}
}
int merge(int x,int y){
if(!x || !y) return x | y;
push_down(x),push_down(y);
if(s[x].key < s[y].key){
s[x].r = merge(s[x].r,y);
return x;
}
else{
s[y].l = merge(x,s[y].l);
return y;
}
}
void suball(int x,int &y,int z){
if(!x) return;
push_down(x);
suball(s[x].l,y,z);
suball(s[x].r,y,z);
s[x].l = s[x].r = 0;
s[x].val -= z,s[x].cnt++;
int rt1,rt2;
split(y,s[x].val,rt1,rt2);
y = merge(merge(rt1,x),rt2);
}
void insert(int x,int id){
int rt1,rt2;
split(root,x,rt1,rt2);
ncnt++;
s[ncnt].id = id;
s[ncnt].key = Rand();
s[ncnt].val = x;
root = merge(merge(rt1,ncnt),rt2);
}
int ans[maxn];
void query(int x){
if(!x) return;
push_down(x);
ans[s[x].id] = s[x].cnt;
query(s[x].l) , query(s[x].r);
}
int main(){
cin.tie(0) -> sync_with_stdio(0);
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i].c>>a[i].q;
}
sort(a+1,a+n+1);
cin>>m;
for(int i = 1;i <= m;i++){
int x;
cin>>x;
insert(x,i);
}
for(int i = 1;i <= n;i++){
int rt1,rt2,rt3;
split(root,a[i].c-1,rt1,rt2);
split(rt2,a[i].c<<1,rt2,rt3);
if(rt3){
s[rt3].val -= a[i].c;
s[rt3].cnt++;
s[rt3].minlz += a[i].c;
s[rt3].cntlz++;
}
suball(rt2,rt1,a[i].c);
root = merge(rt1,rt3);
}
for(int i = 1;i <= m;i++){
ans[s[i].id] = s[i].cnt;
}
query(root);
for(int i = 1;i <= m;i++){
cout<<ans[i]<<" ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具