2023 0809 模拟赛

\(T\ 1\)

题意简述:

  • \(n\) 条线段,定义线段异或值为它们并的长度减它们交的长度,在其中找到两条有公共点的线段,使得它们的异或值最大。
  • 输入的第一行包括一个正整数 \(n\),表示线段的个数。接下来 \(n\) 行每行包括两个正整数 \(l\) , \(r\) ,表示线段的左右端点。
  • 数据:
    • 对于 \(20\%\) 的数据,满足 \(l\le 300,r\le 300,n\le 300\)
    • 对于 \(40\%\) 的数据,满足 \(n\le 2000\)
    • 对于另外 \(10\%\) 的数据,满足 \(l=1\)
    • 对于 \(100\%\) 的数据,满足 \(1\le n\le 200000,1\le l \le r\le 10^{8}\)

题目解法:

  • 想到线段树
  • 先考虑排个序,考虑以右端点为第一关键字()。
  • 拿一棵线段树维护 \(1\)\(10^{8}\) 的值域,然后依次插入每条线段(的端点)。
  • 考虑两种情况:第一种情况为一条线段包含着另一条线段;第二种情况为两条线段相交。
    • 设两条线段分别为 \(l_1,\ r_1\)\(l_2,\ r_2\)
    • 若线段相交,则答案为 \((r_1-r_2)+(l_1-l_2)\) ,整理得 \((l_1+r_1)-(l_2+r_2)\) 。(假设 \(1\) 线段在 \(2\) 线段的右边)
    • 若线段包含,则答案为 \((r_1-l_1)+(r_2-l_2)\) 。(假设 \(1\) 线段包含 \(2\) 线段)
  • 两种情况若同时统计答案可能有些困难)于是考虑分开统计)
  • 已经以右端点排过序了,那么线段相交的情况中,当前线段视为在右边的线段,要找的最佳答案即为向左找到的所有与当前线段相交的线段中 \((l+r)\) 值最小的线段 \(\Longrightarrow\) 即可以用线段树维护辣。
    具体,考虑将每个点的右端点插入到线段树当中,其值为 \((l+r)\) ,线段树维护一段内的 \(min\) 值。每统计一条线段的答案时,直接查询这条线段区间里面的最小值即可,再用当前线段的 \((l+r)\) 值减去 \(min\) 值。显然以右端点插入时,这条线段的区间里面所统计到的答案一定包含全部线段相交的答案。
    但是,线段包含的也会被统计到,但手画一下即可知道线段包含这么统计,统计出来的答案比真正答案要小,所以并不影响。比如:相交是用当前线段(当前线段为 \(i\)\(l_i+r_i-l_j-r_j\) ,又要求 \(l_j+r_j\) 最小,若包含则为 \((r_i-l_i)-(r_j-l_j)\) 显然以线段相交的方法所统计出来的线段包含答案偏小,因此没有影响。
  • 相应,线段包含即可将线段的左端点插入线段树中,其值为 \(r-l\) ,维护另一个 \(min2\) 值。每统计一条线段的答案时,直接查询这条线段区间里的 \(min2\) 值即可。由于已经以右端点为第一关键字排序过了,查询时显然都是线段包含的答案。
  • 算完当前线段的答案,线段树中插入当前线段的两个值即可)
  • 时间复杂度 \(O(nlogn)\),空间 \(1e8\) 的线段数开不下,需要离散化一下即可。

CODE:

Click
#include<bits/stdc++.h>
using namespace std;
namespace Light_Tea{signed main();}
signed main(){return Light_Tea::main();}
namespace Light_Tea{
#define int long long
void rd(int &n){
    n=0; int f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        n=(n<<3)+(n<<1)+ch-'0';
        ch=getchar();
    }
    n*=f;
}

const int maxn=2e5+5,maxw=5e8;
int n,pos[maxn<<1];
struct line{
    int l,r;
    friend bool operator < (line x,line y){
        return (x.r==y.r)?(x.l<y.l):(x.r<y.r);
    }
}a[maxn];
struct Seg_Tree{
    int minl,minl2;
}tr[maxn<<3];
#define lson(_) (_<<1)
#define rson(_) ((_<<1)|1)
//int cnt=1;

void pushup(int kk){
    tr[kk].minl=min(tr[lson(kk)].minl,tr[rson(kk)].minl);
    tr[kk].minl2=min(tr[lson(kk)].minl2,tr[rson(kk)].minl2);
}

void build(int ll,int rr,int kk){
    if(ll==rr){
        tr[kk].minl=tr[kk].minl2=maxw;
        return ;
    }
    int mid=(ll+rr)>>1;
    build(ll,mid,lson(kk));
    build(mid+1,rr,rson(kk));
    pushup(kk);
}

void update(int ll,int rr,int kk,int xx,int yy){
    if(ll==rr){
        tr[kk].minl=min(tr[kk].minl,yy);
        return ;
    }
    int mid=(ll+rr)>>1;
    if(xx<=mid) update(ll,mid,lson(kk),xx,yy);
    else update(mid+1,rr,rson(kk),xx,yy);
    pushup(kk);
}

int query(int ll,int rr,int kk,int findl,int findr){
    if(ll>=findl&&rr<=findr) return tr[kk].minl;
    int mid=(ll+rr)>>1;
    int cal=maxw;
    if(findl<=mid) cal=min(cal,query(ll,mid,lson(kk),findl,findr));
    if(findr>mid) cal=min(cal,query(mid+1,rr,rson(kk),findl,findr));
    return cal;
}

void update2(int ll,int rr,int kk,int xx,int yy){
    if(ll==rr){
        tr[kk].minl2=min(tr[kk].minl2,yy);
        return ;
    }
    int mid=(ll+rr)>>1;
    if(xx<=mid) update2(ll,mid,lson(kk),xx,yy);
    else update2(mid+1,rr,rson(kk),xx,yy);
    pushup(kk);
}

int query2(int ll,int rr,int kk,int findl,int findr){
    if(ll>=findl&&rr<=findr) return tr[kk].minl2;
    int mid=(ll+rr)>>1;
    int cal=maxw;
    if(findl<=mid) cal=min(cal,query2(ll,mid,lson(kk),findl,findr));
    if(findr>mid) cal=min(cal,query2(mid+1,rr,rson(kk),findl,findr));
    return cal;
}

signed main()
{
    freopen("ut.in","r",stdin);
    freopen("ut.out","w",stdout);
    rd(n);
    int tot=0;
    for(int i=1;i<=n;i++){
        rd(a[i].l), rd(a[i].r);
        pos[++tot]=a[i].l; pos[++tot]=a[i].r;
    }
    sort(a+1,a+1+n);
    sort(pos+1,pos+1+tot);
    int len=unique(pos+1,pos+1+tot)-pos-1;
    // cout << len <<endl;
    build(1,len,1);
    int ans=0;
    for(int i=1;i<=n;i++){
        int ll=lower_bound(pos+1,pos+1+len,a[i].l)-pos;
        int rr=lower_bound(pos+1,pos+1+len,a[i].r)-pos;
        // cout<<ll<<" "<<rr<<endl;
        if(i>1){
            int cal=max(a[i].l+a[i].r-query(1,len,1,ll,rr),a[i].r-a[i].l-(query2(1,len,1,ll,rr)));
            ans=max(ans,cal);
        }
        update(1,len,1,rr,a[i].l+a[i].r);
        update2(1,len,1,ll,a[i].r-a[i].l);
    }
    printf("%lld",ans);
    return 0;
}
}

\(T\ 2\)

题意简述:

https://www.cnblogs.com/Krain428571/p/7426787.html

UPD:2023.10.4 鸽了

posted @ 2023-08-10 09:32  lnbyn  阅读(29)  评论(2编辑  收藏  举报