省选模拟3.9

A. 鱼死网破

看给出的部分分,给出的纵坐标都相同

于是从所有鱼头胖往每个墙的两个端点分别引一条线

覆盖到胖头鱼所在的纵坐标线,可以差分以下,左边的线 \(-1\) 右边的 \(+1\)

可能会有重复覆盖的情况

于是可以用类似括号匹配的方法对每个鱼头胖引出的线进行处理

可以扩展这个做法,只需要将所有线都存到墙的端点里,再按照极角序排序

然后再跟胖头鱼的连线比较二分一下,就能知道要减或者加多少个 \(1\)

可以用叉积来进行极角序排序

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,k,m,op;
int x[100010],y[100010];
int l[60],r[60],h[60];
struct data{int x,y;inline bool operator<(const data &b)const{return 1ll*(1ll*x*b.y-1ll*y*b.x)>0ll;}};
struct dddd{int x,y,k,l;inline bool operator<(const dddd &b)const{return 1ll*(1ll*x*b.y-1ll*y*b.x)>0ll;}};
vector<data>vec[110];
vector<dddd>v;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("clash.in","r",stdin);
	freopen("clash.out","w",stdout);
	n=read(),k=read(),m=read(),op=read();
	for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
	for(int i=1;i<=k;i++) l[i]=read(),r[i]=read(),h[i]=read();
	for(int i=1;i<=n;i++){
		v.clear();
		for(int j=1;j<=k;j++) if(y[i]>h[j]){
			v.emplace_back((dddd){l[j]-x[i],h[j]-y[i],-1,j});
			v.emplace_back((dddd){r[j]-x[i],h[j]-y[i], 1,j});
		}
		sort(v.begin(),v.end());
		for(int j=0,L=0,R=0,k=0;j<v.size();j++){
			if(v[j].k==-1) k--;
			if(v[j].k== 1) k++;
			if(k==-1&&v[j].k==-1) L=j;
			if(k== 0&&v[j].k== 1){
				R=j;
				vec[v[L].l*2  ].emplace_back((data){v[L].x,v[L].y});
				vec[v[R].l*2+1].emplace_back((data){v[R].x,v[R].y});
			}
		}
	}
	for(int i=2;i<=k*2+1;i++) sort(vec[i].begin(),vec[i].end());
	for(int i=1,x,y,res=0;i<=m;i++){
		x=read()^(res*op),y=read()^(res*op);res=n;
		for(int j=1,vv;j<=k;j++){
			vv=upper_bound(vec[j*2  ].begin(),vec[j*2  ].end(),(data){x-l[j],y-h[j]})-vec[j*2  ].begin();res-=vv;
			vv=lower_bound(vec[j*2+1].begin(),vec[j*2+1].end(),(data){x-r[j],y-h[j]})-vec[j*2+1].begin();res+=vv;
		}
		printf("%d\n",res);
	}
	return 0;
}

B. 漏网之鱼

正着添加一个数,修改的位置总共 \(O(n)\) 个,可以根据这个做,我不太会

于是考虑倒着删除一个数

那修改的区间肯定是他上一次出现的位置一直往前直到 \(mex = a_i\)

可以用线段树上二分找到这个位置

那现在就要维护区间赋值和区间历史值和

线段树上每个节点维护两个信息,一个是当前的 \(mex\) 一个是 \(sum\)

\(sum\) 表示的就是以当前位置为左端点,右端点在现在枚举的位置到 \(n\) 的区间的 \(mex\) 值和

用类似扫描线的思路把询问离线下来

拆成 \(l\)\(r+1\) 分别询问 \([l,r]\) 的值然后造成 \(+1,-1\) 的贡献

具体维护,我用了 \(3\) 个标记

分别是 \(c,u,v\) 分别表示累加次数,赋值标记,在赋值标记后的累加贡献

下传时先 \(c\)\(u\)\(v\) 无所谓

下传 \(c\) 时要先判断左右儿子有没有 \(u\) ,有的话就转成 \(v\) 没有就正常下传

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,q,blo;
int a[1000010],pre[1000010],lst[1000010];
bool vis[1000010];
int ans[1000010],mex[1000010];
int bl[1000010],v[1000010];
int L[1010],R[1010];
int sum[1010],vsum[1010],utag[1010],ctag[1010],vtag[1010],mx[1010];
struct data{int l,r,k,id;};
vector<data>vec[1000010];
struct seg{
	int mx;
	int sum,vsum;
	int utag,ctag,vtag;
}st[1000010*4];
inline void pushup(int rt){
	st[rt].mx=max(st[lson].mx,st[rson].mx);
	st[rt].sum=st[lson].sum+st[rson].sum;
	st[rt].vsum=st[lson].vsum+st[rson].vsum;
}
inline void pushdown(int rt,int l,int r){
	int mid=(l+r)>>1;
	if(st[rt].ctag){
		st[lson].vsum+=st[lson].sum*st[rt].ctag;
		st[rson].vsum+=st[rson].sum*st[rt].ctag;
		if(st[lson].utag!=-1) st[lson].vtag+=st[lson].utag*st[rt].ctag;else st[lson].ctag+=st[rt].ctag;
		if(st[rson].utag!=-1) st[rson].vtag+=st[rson].utag*st[rt].ctag;else st[rson].ctag+=st[rt].ctag;
		st[rt].ctag=0;
	}
	if(st[rt].utag!=-1){
		st[lson].utag=st[rson].utag=st[rt].utag;
		st[lson].mx=st[rson].mx=st[rt].utag;
		st[lson].sum=st[rt].utag*(mid-l+1);
		st[rson].sum=st[rt].utag*(r-mid);
		st[rt].utag=-1;
	}
	if(st[rt].vtag){
		st[lson].vsum+=st[rt].vtag*(mid-l+1);
		st[rson].vsum+=st[rt].vtag*(r-mid);
		st[lson].vtag+=st[rt].vtag;
		st[rson].vtag+=st[rt].vtag;
		st[rt].vtag=0;
	}
}
void build(int rt,int l,int r){
	st[rt].utag=-1;if(l==r) return st[rt].mx=st[rt].sum=st[rt].vsum=mex[l],void();
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(rt);
}
void upd(int rt,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R) return st[rt].mx=st[rt].utag=k,st[rt].sum=(r-l+1)*k,void();
	int mid=(l+r)>>1;pushdown(rt,l,r);
	if(L<=mid) upd(lson,l,mid,L,R,k);
	if(R>mid) upd(rson,mid+1,r,L,R,k);
	pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return st[rt].vsum;
	int mid=(l+r)>>1,res=0;pushdown(rt,l,r);
	if(L<=mid) res+=query(lson,l,mid,L,R);
	if(R>mid) res+=query(rson,mid+1,r,L,R);
	pushup(rt);return res;
}
int getpos(int rt,int l,int r,int k){
	if(st[rt].mx<k) return -1;if(l==r) return l;
	int mid=(l+r)>>1;pushdown(rt,l,r);
	if(st[rson].mx>k) return getpos(rson,mid+1,r,k);
	else return getpos(lson,l,mid,k);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("escape.in","r",stdin);
	freopen("escape.out","w",stdout);
	read();n=read();for(int i=1;i<=n;i++) a[i]=read();blo=sqrt(n);
	for(int i=1;i<=n;i++) if(a[i]<=n){pre[i]=lst[a[i]];lst[a[i]]=i;}
	for(int i=n,v=0;i;i--){
		if(a[i]<=n) vis[a[i]]=1;
		while(vis[v]) v++;mex[i]=v;
	}
	build(1,1,n);q=read();
	for(int i=1,l,r;i<=q;i++){
		l=read(),r=read();
		vec[l].emplace_back((data){l,r,1,i});
		vec[r+1].emplace_back((data){l,r,-1,i});
	}
	for(int i=n,l,r;i;i--){
		for(auto L:vec[i]) ans[L.id]+=L.k*query(1,1,n,L.l,L.r);
		if(a[i]<=n){
			l=pre[i]+1,r=getpos(1,1,n,a[i]);
			if(l<=r) upd(1,1,n,l,r,a[i]);
		}
		if(st[1].utag!=-1) st[1].vtag+=st[1].utag,st[1].vsum+=st[1].utag*n;
		else st[1].ctag++,st[1].vsum+=st[1].sum;
	}
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	return 0;
}

C. 浑水摸鱼

转化一下,就是求本质不同子串个数,一般用 \(SA\) 或者 \(SAM\)

由于最小表示法,所以用 \(SA\) 来求

比较时,先二分求出 \(lcp\) 再比较下一位的值

将字符串的哈希定义为每个字符与他前一个相同的字符相差的距离

用主席树存下每一个后缀的哈希值

排完序后直接求本质不同子串个数

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define cmin(x,y) ((x)<(y))?(x):(y)
#define uint unsigned long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans;
int a[50010],t[50010];
int rt[50010],lst[50010],tot;
int pre[50010],nxt[50010],v[50010];
uint pw[50010];
struct seg{int ls,rs;uint hs;}st[50010*20];
inline void pushup(int x,int l,int r){int mid=(l+r)>>1;st[x].hs=st[st[x].ls].hs+st[st[x].rs].hs*pw[mid-l+1];}
void build(int &x,int l,int r){
	x=++tot;if(l==r) return st[x].hs=v[l],void();
	int mid=(l+r)>>1;
	build(st[x].ls,l,mid);
	build(st[x].rs,mid+1,r);
	pushup(x,l,r);
}
void upd(int &x,int l,int r,int pos,uint k){
	int pre=x;x=++tot;st[x]=st[pre];if(l==r) return st[x].hs=k,void();
	int mid=(l+r)>>1;
	if(pos<=mid) upd(st[x].ls,l,mid,pos,k);
	else upd(st[x].rs,mid+1,r,pos,k);
	pushup(x,l,r);
}
uint query(int x,int l,int r,int L,int R){
	if(L<=l&&r<=R) return st[x].hs;int mid=(l+r)>>1;
	if(R<=mid) return query(st[x].ls,l,mid,L,R);
	if(L>mid) return query(st[x].rs,mid+1,r,L,R);
	return query(st[x].ls,l,mid,L,R)+query(st[x].rs,mid+1,r,L,R)*pw[cmin(mid-L+1,mid-l+1)];
}
inline int getlcp(int x,int y){
	int lenx=n-x+1,leny=n-y+1;
	int l=1,r=cmin(lenx,leny),res=0;
	while(l<=r){
		int mid=(l+r)>>1;
		if(query(rt[x],1,n,x,x+mid-1)==query(rt[y],1,n,y,y+mid-1)) l=mid+1,res=mid;
		else r=mid-1;
	}
	return res;
}
inline int s(int x,int k){return (pre[k]>=x)?k-pre[k]+1:1;}
inline bool cmp(int x,int y){
	int lenx=n-x+1,leny=n-y+1;
	int l=1,r=cmin(lenx,leny),res=0;
	while(l<=r){
		int mid=(l+r)>>1;
		if(query(rt[x],1,n,x,x+mid-1)==query(rt[y],1,n,y,y+mid-1)) l=mid+1,res=mid;
		else r=mid-1;
	}
	if(res==min(lenx,leny)) return lenx<leny;
	return s(x,x+res)<s(y,y+res);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("waterflow.in","r",stdin);
	freopen("waterflow.out","w",stdout);
	pw[0]=1;for(int i=1;i<=50000;i++) pw[i]=pw[i-1]*131;
	n=read();for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++){nxt[pre[i]=lst[a[i]]]=i;lst[a[i]]=i;}
	for(int i=1;i<=n;i++){
		if(pre[i]) v[i]=i-pre[i]+1;else v[i]=1;
	}
	build(rt[1],1,n);
	for(int i=2;i<=n;i++){
		rt[i]=rt[i-1];
		if(nxt[i-1]) upd(rt[i],1,n,nxt[i-1],1);
	}
	for(int i=1;i<=n;i++) t[i]=i;
	stable_sort(t+1,t+1+n,cmp);ans=n-t[1]+1;
	for(int i=2;i<=n;i++){ans+=n-t[i]+1;ans-=getlcp(t[i-1],t[i]);}
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-03-10 09:32  Max_QAQ  阅读(59)  评论(0编辑  收藏  举报