1. 程式人生 > 其它 >省選模擬3.9

省選模擬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;
}