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