20241218北京总结

扫描线

构建模型的主要思想 : 把问题换到平面上

二维数点 , 就是通过差分和扫描线将问题降维的问题

来看看题

Recommendations

不难发现问题其实是求包含这个区间的区间中 \(min_r\)\(max_l\)

直接以 \(l,r\) 为轴建立坐标 , 完了就是扫描线裸题

当然 , 这个题还可以平衡树搞过 , 毕竟是求后继与前驱

#include<bits/stdc++.h>
using namespace std;
struct Node{
    int x,y,id;
} a[11000000];
struct Query{
    int lans,rans,len;
} q[11000000];
bool cmp1(Node f,Node s){
    return f.x<s.x;
}
bool cmp2(Node f,Node s){
    return f.y>s.y;
}
multiset<int> s;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i].x>>a[i].y;
            a[i].id=i;
            q[i].len=a[i].y-a[i].x+1;
        }
        sort(a+1,a+n+1,cmp1);
        s.clear();
        for(int i=1;i<=n;i++){
            int lst=i;
            s.insert(a[i].y);
            while(a[i].x==a[i+1].x and i+1<=n){
                s.insert(a[++i].y);
            }
            for(int j=lst;j<=i;j++){
                auto it=s.lower_bound(a[j].y);
                it++;
                if(it==s.end()){
                    q[a[j].id].rans=-1;
                }else{
                    q[a[j].id].rans=*it;
                }
            }
        }
        s.clear();
        sort(a+1,a+n+1,cmp2);
        for(int i=1;i<=n;i++){
            int lst=i;
            s.insert(a[i].x);
            while(a[i].y==a[i+1].y and i+1<=n){
                s.insert(a[++i].x);
            }
            for(int j=lst;j<=i;j++){
                auto it=s.upper_bound(a[j].x);
                it--;it--;
                if(it==s.end()){
                    q[a[j].id].lans=-1;
                }else{
                    q[a[j].id].lans=*it;
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(q[i].lans==-1 or q[i].rans==-1){
                cout<<"0\n";
                continue;
            }
            cout<<q[i].rans-q[i].lans+1-q[i].len<<'\n';
            q[i].lans=q[i].rans=q[i].len=0;
            a[i].id=a[i].x=a[i].y=0;
        }
    }
    return 0;
}

the soldier of love

正难则反 , 我们直接把问题变为一个都不包含

考虑没有点的区间表示出来 , 记为 \([l,r]\) ,如果我们想没有点的话 \(l\leq L\) , \(r\geq R\) , 把它放到平面上

矩形显然有 \(n+1\) 个 , 复杂度 \(O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;
struct Node{
    int x,y,id;
} a[11000000];
struct Query{
    int lans,rans,len;
} q[11000000];
bool cmp1(Node f,Node s){
    return f.x<s.x;
}
bool cmp2(Node f,Node s){
    return f.y>s.y;
}
multiset<int> s;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i].x>>a[i].y;
            a[i].id=i;
            q[i].len=a[i].y-a[i].x+1;
        }
        sort(a+1,a+n+1,cmp1);
        s.clear();
        for(int i=1;i<=n;i++){
            int lst=i;
            s.insert(a[i].y);
            while(a[i].x==a[i+1].x and i+1<=n){
                s.insert(a[++i].y);
            }
            for(int j=lst;j<=i;j++){
                auto it=s.lower_bound(a[j].y);
                it++;
                if(it==s.end()){
                    q[a[j].id].rans=-1;
                }else{
                    q[a[j].id].rans=*it;
                }
            }
        }
        s.clear();
        sort(a+1,a+n+1,cmp2);
        for(int i=1;i<=n;i++){
            int lst=i;
            s.insert(a[i].x);
            while(a[i].y==a[i+1].y and i+1<=n){
                s.insert(a[++i].x);
            }
            for(int j=lst;j<=i;j++){
                auto it=s.upper_bound(a[j].x);
                it--;it--;
                if(it==s.end()){
                    q[a[j].id].lans=-1;
                }else{
                    q[a[j].id].lans=*it;
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(q[i].lans==-1 or q[i].rans==-1){
                cout<<"0\n";
                continue;
            }
            cout<<q[i].rans-q[i].lans+1-q[i].len<<'\n';
            q[i].lans=q[i].rans=q[i].len=0;
            a[i].id=a[i].x=a[i].y=0;
        }
    }
    return 0;
}

UOJ637 数据结构

同样正难则反 , 考虑每个数什么时候才不会被算入贡献 .

就是所有该数都被加一 , 所有该数减一都没被区间包含

也就是说对于 \(x\) , \(l\leq min_x\) \(and\) \(r\geq max_x\)

并且对于不含 \(x-1\) 的区间 \([L,R]\) , \(l\leq L\) , \(r\geq R\)

我们发现第一个限制条件同第一道题 , 第二个同第二道题 , 直接维护就行

#include<bits/stdc++.h>
using namespace std;
struct Node{
    int x,y;
} a[1100000];
int n,m;
struct BitArray{
    int f[1100000];
    void init(){
        memset(f,0,sizeof(f));
    }
    int lowbit(int x){
        return x&(-x);
    }
    void modify(int x,int val){
        //cout<<x<<"\n";
        while(x<=n){
            f[x]+=val;
            x=x+lowbit(x);
        }
    }
    int query(int x){
        int res=0;
        while(x){
            res=res+f[x];
            x=x-lowbit(x);
        }
        return res;
    }
}BA;
int ans[1100000];
vector<int> g[1100000];
int val[1100000];
int maxx[1100000];
int cnt=0;
int lst[1100000];
bool vis[1100000];
int nxt[1100000];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>val[i];
    }
    for(int i=n;i>=1;i--){
        if(lst[val[i]]){
            nxt[i]=lst[val[i]];
        }else{
            maxx[val[i]]=i;
            nxt[i]=n+1;
        }
        lst[val[i]]=i;
    }
    for(int i=0;i<=n;i++){
        if(not lst[i]){
            lst[i]=n+1;
        }
    }
    for(int i=1;i<=n+1;i++){
		if(maxx[i]){
            BA.modify(1,1);
            BA.modify(maxx[i],-1);
        }
		BA.modify(max(lst[i-1],maxx[i]),1);
        BA.modify(n+1,-1);
	}
    for(int i=1;i<=m;i++){
        cin>>a[i].x>>a[i].y;
        g[a[i].x].push_back(i);
    }
    for(int i=1;i<=n;i++){
		for(int j:g[i]){
            ans[j]=BA.query(a[j].y);
        }
		lst[val[i]]=nxt[i];
		if(!vis[val[i]]){
			vis[val[i]]=true;
            if(maxx[val[i]]<lst[val[i]-1]){
                BA.modify(maxx[val[i]],1);
                BA.modify(lst[val[i]-1],-1);
            }
		}
		if(!vis[val[i]+1]){
            BA.modify(max(i,maxx[val[i]+1]),-1);
            BA.modify(n+1,+1);
            BA.modify(max(lst[val[i]],maxx[val[i]+1]),1);
            BA.modify(n+1,-1);
		}
	}
    for(int i=1;i<=m;i++){
        cout<<ans[i]<<"\n";
    }
    return 0;
}

函数复合

这是一类问题的 \(trick\) (?) , 具体而言 , 每次询问给定一个区间 \([l,r]\) 和初始值 \(x\) ,求 \(F_r(...F_l(x))\)

接下来我们考虑 插入-标记-回收算法 , 我个人理解上就是把询问离线后上扫描线 , 用数据结构维护函数值 , \(l\) 插入 , \(r\) 提取出来

标记永久化

不会树套树 , 待学

image

image

posted @ 2024-12-19 20:58  2019yyy  阅读(14)  评论(0)    收藏  举报