基于惨痛教训,最后10分(10-11测试点)调了一下午加一晚上。。。
*别偷懒了,该对拍就对拍吧。。。
CCF-CSP 202303 星际网络Ⅱ题解
题意
有一段长度为n的二进制地址(表示为16进制,即有效长度为n/4),给定三种如下操作,进行对应输出:
- 向用户号为id的用户分配[l,r]长度的地址,若(为空)或(非满且该段先前分配部分均面向id)则可分配,进行分配并输出YES;否则输出NO
- 查看特定地址s是否分配给了某个用户,是则输出用户id;反之输出0
- 查看特定地址段是否全部分配给了某个单一用户,若是则输出用户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),而不会添加新的元素。
线段树
线段树节点保存如下内容:
- 当前区间分配用户id最大值 bh
- 当前区间分配用户id最小值 bl
- 当前区间已分配长度(离散后长度) ct
所以对三种操作,做以下解答:
- 地址段分配长度小于地址段长度,且未分配或 b h = = b l = = 当前用户 i d bh==bl==当前用户id bh==bl==当前用户id,此时可分配;反之不可分配。
- bh==bl时输出bh;反之输出0
- 段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;
}