CCF-CSP 202303 星际网络Ⅱ 90=>100题解

基于惨痛教训,最后10分(10-11测试点)调了一下午加一晚上。。。

*别偷懒了,该对拍就对拍吧。。。


CCF-CSP 202303 星际网络Ⅱ题解

题意

有一段长度为n的二进制地址(表示为16进制,即有效长度为n/4),给定三种如下操作,进行对应输出:

  1. 向用户号为id的用户分配[l,r]长度的地址,若(为空)或(非满且该段先前分配部分均面向id)则可分配,进行分配并输出YES;否则输出NO
  2. 查看特定地址s是否分配给了某个用户,是则输出用户id;反之输出0
  3. 查看特定地址段是否全部分配给了某个单一用户,若是则输出用户id;反之输出0

题解

明显的离散化+线段树:

离散化

将操作一、二、三中分布于 2 n 2^n 2n级别区域的地址映射为O(q)级别,而后排序,去重。

特别注意: 为了防止[1,2],[4,5]离散后变为[1,2],[3,4]而导致后续地址段[2,4]不可分,我们需要在一对一映射基础上进行额外操作。

  • 错误操作:一对二映射即每两个原元素间插入新的元素,这样会导致[1,2],[3,4]分配后,[2,3]仍可分,故不可取。
  • 正确操作(例):仍采用一对一映射,对操作1、3的右边界采取加1操作,此时我们每次操作/查询的地址段由[l,r]变为[l,r),而不会添加新的元素。

线段树

线段树节点保存如下内容:

  1. 当前区间分配用户id最大值 bh
  2. 当前区间分配用户id最小值 bl
  3. 当前区间已分配长度(离散后长度) ct

所以对三种操作,做以下解答:

  1. 地址段分配长度小于地址段长度,且未分配或 b h = = b l = = 当前用户 i d bh==bl==当前用户id bh==bl==当前用户id,此时可分配;反之不可分配。
  2. bh==bl时输出bh;反之输出0
  3. 段bh==bl且满时输出bh,反之输出0

特别注意:线段树操作前不能偷懒的利用全局变量为0的特点,建树操作以赋初始bh值为负无穷,bl为正无穷是有必要的。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#define ll long long
#define lson rec<<1,l,mid
#define rson rec<<1|1,mid+1,r
using namespace std;
const int mx=1e6,maxn=600,maxq=100005,zwq=1e9,fwq=-1e9;
int n,q,nm,pn;
int fx,fy,fz;
bool spj;
int bh[mx],bl[mx],ct[mx],pw[maxq],tid[maxq];
char s[maxn];
struct node{
    int cz,id;
    int l,r;
}op[maxq];
struct nd{
	int wn;
	int a[33];
}st[maxq];
inline int htn(char ch){
    if(ch>='0'&&ch<='9') return ch-48;
    else return ch+10-'a';
}
inline int getAddr(int ad=0){
    scanf("%s",s);
    int l =strlen(s);
    ++nm;pw[nm]=nm;
    int nt=0,mp=0;
    for(int i=0;i<l;++i) if(s[i]==':') ++mp;
    st[nm].wn=mp;
    for(int i=0;i<l;++i){
        if(s[i]==':'){
        	st[nm].a[mp]=nt;
        	nt=0;--mp;
		}
        else nt=nt*16+htn(s[i]);
    }
    st[nm].a[mp]=nt+ad;
    while(st[nm].a[mp]>=65536){
    	st[nm].a[mp]-=65536;
    	++mp;++st[nm].a[mp];
    	if(mp>st[nm].wn) st[nm].wn=mp;
	}
    return nm;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    return x*f;
}
void pushdown(int rec,int l,int r){
    if(bh[rec]==bl[rec]&&ct[rec]==r-l+1){
    	bh[rec<<1]=bh[rec<<1|1]=bl[rec<<1]=bl[rec<<1|1]=bh[rec];
    	int mid=(l+r)>>1;
    	ct[rec<<1]=mid-l+1;ct[rec<<1|1]=r-mid;
    }
}
void modify(int rec,int l,int r){
    if(fx<=l&&r<=fy){
    	bl[rec]=bh[rec]=fz;ct[rec]=r-l+1;
        return;
    }
    int mid=(l+r)>>1;pushdown(rec,l,r);
    if(fx<=mid) modify(lson);
    if(fy>mid) modify(rson);
    bh[rec]=max(bh[rec<<1],bh[rec<<1|1]);
    bl[rec]=min(bl[rec<<1],bl[rec<<1|1]);
    ct[rec]=ct[rec<<1]+ct[rec<<1|1];
}
int queryMx(int rec,int l,int r){
    if(fx<=l&&r<=fy) return bh[rec];
    int mid=(l+r)>>1;pushdown(rec,l,r);
    if(fx>mid) return queryMx(rson);
    else if(fy<=mid) return queryMx(lson);
    return max(queryMx(lson),queryMx(rson));
}
int queryMn(int rec,int l,int r){
	if(fx<=l&&r<=fy) return bl[rec];
	int mid=(l+r)>>1;pushdown(rec,l,r);
	if(fx>mid) return queryMn(rson);
	else if(fy<=mid) return queryMn(lson);
	return min(queryMn(lson),queryMn(rson));
}
int queryFull(int rec,int l,int r){
	if(fx<=l&&r<=fy) return ct[rec];
    int mid=(l+r)>>1;pushdown(rec,l,r);
    if(fx>mid) return queryFull(rson);
    else if(fy<=mid) return queryFull(lson);
    return queryFull(lson)+queryFull(rson);
}
int getIdx(int ip){
	return tid[ip];//(tid[ip]<<1)-1;
} 
inline bool cmp(int a,int b){
	int tw=max(st[a].wn,st[b].wn);
	for(int i=tw;i>=0;--i){
		if(st[a].a[i]==st[b].a[i]) continue;
		return st[a].a[i]<st[b].a[i];
	}
	return false;
}
inline bool cmpEq(int a,int b){
	int tw=max(st[a].wn,st[b].wn);
	for(int i=tw;i>=0;--i){
		if(st[a].a[i]==st[b].a[i]) continue;
		return false;
	}
	return true;
}
void qkSort(int lid,int rid){
	int l=lid,r=rid,mid=pw[(l+r)>>1];
	while(l<=r){
		while(cmp(pw[l],mid)) ++l;
		while(cmp(mid,pw[r])) --r;
		if(l<=r){
			swap(pw[l],pw[r]);++l;--r;
		}
	}
	if(r>lid) qkSort(lid,r);
	if(l<rid) qkSort(l,rid);
}
inline void build(int rec,int l,int r){
	bh[rec]=fwq;bl[rec]=zwq;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(lson);build(rson);
}
int main(){
    n=read();q=read();
    for(int i=1;i<=q;++i){
        op[i].cz=read();
        if(op[i].cz==1){
            op[i].id=read();
            op[i].l=getAddr();
            op[i].r=getAddr(1);
        }
        else if(op[i].cz==2){
            op[i].l=getAddr();
        }
        else{
            op[i].l=getAddr();op[i].r=getAddr(1);
        }
    }
    qkSort(1,nm);
    int cp=0;
    for(int i=1;i<=nm;++i){
    	if(i>1&&cmpEq(pw[i],pw[i-1])){
    		tid[pw[i]]=tid[pw[i-1]];
		}
    	else{
    		tid[pw[i]]=++cp;pw[cp]=pw[i];
		} 
	}
	nm=cp;
	build(1,1,nm);
    for(int i=1;i<=q;++i){
        if(op[i].cz==1){
            fx=op[i].l;fy=op[i].r;fz=op[i].id;
            fx=getIdx(fx);fy=getIdx(fy)-1;
            if(queryFull(1,1,nm)==fy-fx+1) printf("NO\n");
            else{
                int qh=queryMx(1,1,nm),ql=queryMn(1,1,nm);
                if((qh<ql)||(qh==ql&&qh==fz)){
                    printf("YES\n");
                    modify(1,1,nm);
                }
                else printf("NO\n");
            }
        }
        else if(op[i].cz==2){
            fx=op[i].l;fy=fx;
            fx=getIdx(fx);fy=getIdx(fy);
            int nid=queryMx(1,1,nm);
            if(nid<0) nid=0;
            printf("%d\n",nid);
        }
        else{
            fx=op[i].l;fy=op[i].r;
            fx=getIdx(fx);fy=getIdx(fy)-1;
            if(queryFull(1,1,nm)==fy-fx+1){
                int nid=queryMx(1,1,nm),pid=queryMn(1,1,nm);
                if(nid==pid) printf("%d\n",nid);
                else printf("0\n");
            }
            else printf("0\n");
        }
    }
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hiroxzwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值