【考试总结】2022-05-04
路人女主
势不两立的串对与以下两种形成双射(下述 \(ABC\) 是其六种轮换之一):
-
S=ABABABA
,\(T\) 的奇数位置是 \(C\),偶数位置是 \(A/B\) -
\(S,T\) 的偶数位置是 \(C\),奇数位置满足存在一个 \(k\) 使得 \(s\) 的前 \(k\) 个奇数位置为 \(A\),后面的奇数位置为 \(B\),而 \(t\) 恰好相反:前 \(k\) 个奇数位置为 \(B\),后面的奇数位置为 \(A\)
Code Display
char s[N<<1],t[N<<1];
int ans,n;
bool sufs[N<<1],suft[N<<1];
inline bool check(char A,char B){return A==B||A=='?';}
inline void solve(char A,char B,char C){
bool Fail=0;
int m=n<<1|1;
for(int i=1;i<=m&&!Fail;++i){
if((i&1)&&!check(s[i],A)) Fail=1;
if(!(i&1)&&!check(s[i],B)) Fail=1;
}
for(int i=1;i<=m&&!Fail;i+=2) if(!check(t[i],C)) Fail=1;
for(int i=2;i<=m&&!Fail;i+=2) if(!check(t[i],A)&&!check(t[i],B)) Fail=1;
if(!Fail){
int cnt=0;
for(int i=2;i<=m;i+=2) cnt+=t[i]=='?';
ckadd(ans,ksm(2,cnt));
}else Fail=0;
for(int i=1;i<=m&&!Fail;++i){
if((i&1)&&!check(t[i],A)) Fail=1;
if(!(i&1)&&!check(t[i],B)) Fail=1;
}
for(int i=1;i<=m&&!Fail;i+=2) if(!check(s[i],C)) Fail=1;
for(int i=2;i<=m&&!Fail;i+=2) if(!check(s[i],A)&&!check(s[i],B)) Fail=1;
if(!Fail){
int cnt=0;
for(int i=2;i<=m;i+=2) cnt+=s[i]=='?';
ckadd(ans,ksm(2,cnt));
}else Fail=0;
for(int i=2;i<=m&&!Fail;i+=2) if(!check(s[i],C)||!check(t[i],C)) Fail=1;
sufs[m+2]=suft[m+2]=1;
for(int i=m;i>=1;i-=2){
sufs[i]=sufs[i+2]&check(s[i],B);
suft[i]=suft[i+2]&check(t[i],A);
}
for(int i=1;i
铃原露露
对于树上三个点 \(\rm z=lca(x,y)\) 那么如果 \(a_z 那么对于 \(l\in(a_z,a_x],r\in[a_y,n]\) 这样子的区间 \([l,r]\) 都是非法的,类似的 \(a_x 的结构会导致 \(l\in[1,a_x],r\in[a_y,a_z)\) 不合法
那么可以使用启发式合并维护所有的 \(a_x\) 想要找到上面描述的矩形利用覆盖关系所需要的就是每个元素在其它子树里面的前驱后继
剩下的工作是一个线段树维护历史为 \(0\) 的次数的和,而这是平凡的
Code Display
const int N=2e5+10;
set sub[N];
int n,Q;
struct Segment_Tree{
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
int num[N<<2],sum[N<<2],Mn[N<<2];
int plu[N<<2],tim[N<<2];
inline void push_up(int p){
sum[p]=sum[ls]+sum[rs];
Mn[p]=min(Mn[ls],Mn[rs]);
num[p]=0;
if(Mn[p]==Mn[ls]) num[p]+=num[ls];
if(Mn[p]==Mn[rs]) num[p]+=num[rs];
return ;
}
inline void push_add(int p,int v){plu[p]+=v,Mn[p]+=v;}
inline void push_tim(int p,int v){sum[p]+=num[p]*v,tim[p]+=v;}
inline void push_down(int p){
if(tim[p]){
int Min=min(Mn[ls],Mn[rs]);
if(Min==Mn[ls]) push_tim(ls,tim[p]);
if(Min==Mn[rs]) push_tim(rs,tim[p]);
tim[p]=0;
}
if(plu[p]){
push_add(ls,plu[p]);
push_add(rs,plu[p]);
plu[p]=0;
}
return ;
}
inline void upd(int st,int ed,int v,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return push_add(p,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) upd(st,ed,v,lson);
if(ed>mid) upd(st,ed,v,rson);
return push_up(p);
}
inline int query(int st,int ed,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return sum[p];
int mid=(l+r)>>1,res=0; push_down(p);
if(st<=mid) res+=query(st,ed,lson);
if(ed>mid) res+=query(st,ed,rson);
return res;
}
inline void incr(int st,int ed,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return push_tim(p,Mn[p]==0);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) incr(st,ed,lson);
if(ed>mid) incr(st,ed,rson);
return push_up(p);
}
inline void build(int p,int l,int r){
num[p]=r-l+1;
if(l==r) return ;
int mid=(l+r)>>1;
build(lson); build(rson);
}
#undef ls
#undef rs
#undef lson
#undef rson
}T;
int a[N],ans[N];
vector >qu[N];
vector G[N];
vector >squ[N];
inline void ins(int sx,int ex,int sy,int ey){
squ[sy].emplace_back(sx,ex,1);
squ[ey+1].emplace_back(sx,ex,-1);
}
inline void dfs(int x){
int son=0;
for(auto t:G[x]){
dfs(t);
if(sub[t].size()>sub[son].size()) son=t;
}
swap(sub[x],sub[son]);
for(auto t:G[x]) if(t!=son){
for(auto v:sub[t]){
auto iter=sub[x].upper_bound(v);
if(v>a[x]){
if(iter!=sub[x].end()){
ins(a[x]+1,v,*iter,n);
}
if(iter!=sub[x].begin()){
--iter;
if(*iter>a[x]){
ins(a[x]+1,*iter,v,n);
}
}
}else{
if(iter!=sub[x].end()){
if(*iter
赫露艾斯塔
这个题本质上是在求一个半平面上偏序对数量
注意到直线斜率不超过 \(0\) 时可以预处理出来每个点被偏序以及偏序其它元素的次数然后做半平面上的元素求和
而对于直线斜率为正的情况,此时不构成偏序的元素是具有传递性的,所以可以进行容斥计算
对于半平面上权值和这一问题可以将每个维度分成 \(\sqrt {\rm n}\) 个块,并对每行的块做前缀和
对于一条直线,它横穿的块的个数不超过 \(\sqrt n\),而又在数据随机的情况下每个块里面期望 \(\Theta(1)\) 个点,所以可以暴力扫
Code Display
const int D=1e4+1,N=2e5+10;
int bel[N],lef[N],rig[N];
struct Fenwick_Tree{
int c[N];
inline void insert(int x,int v){
x+=D;
for(;x<=(D<<1);x+=x&(-x)) c[x]+=v;
return ;
}
inline int query(int x){
x+=D;
int res=0;
for(;x;x-=x&(-x)) res+=c[x];
return res;
}
inline int query(int l,int r){return query(r)-query(l-1);}
inline void clear(){memset(c,0,sizeof(c));}
}T;
const int BL=150,Bcnt=200,Cmax=1e4;
ll A,B,C;
int n,Q;
pair cor[N];
double k,b;
namespace spj{
int pre[N],suf[N];
inline void init(){
for(int i=1;i<=n;++i){
int j=i;
while(j<=n&&cor[i].fir==cor[j].fir) ++j;
--j;
for(int k=i;k<=j;++k) pre[k]=pre[k-1]+T.query(-1e4,cor[k].sec-1);
for(int k=i;k<=j;++k) T.insert(cor[k].sec,1);
i=j;
}
T.clear();
for(int i=n;i>=1;--i){
int j=i;
while(j&&cor[j].fir==cor[i].fir) --j;
++j;
for(int k=i;k>=j;--k) suf[k]=suf[k+1]+T.query(cor[k].fir+1,1e4);
for(int k=i;k>=j;--k) T.insert(cor[k].sec,1);
i=j;
}
T.clear();
}
inline void solve(){
if(A<0){
int l=1,r=n,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(cor[mid].fir*A+C>0) ans=mid,l=mid+1;
else r=mid-1;
}
print(pre[ans]);
}else{
int l=1,r=n,ans=n+1;
while(l<=r){
int mid=(l+r)>>1;
if(cor[mid].fir*A+C>0) ans=mid,r=mid-1;
else l=mid+1;
}
print(suf[ans]);
}
}
}
inline int get_block(ll x){
ll y=k*x+b;
if(y<-Cmax) return 0;
if(y>Cmax) return bel[Cmax+D]+1;
return bel[y+D];
}
vector node[Bcnt][Bcnt];
struct Block{
ll sum[Bcnt][Bcnt];
int w[N];
inline void init(){
for(int i=1;i<=n;++i) sum[bel[cor[i].fir+D]][bel[cor[i].sec+D]]+=w[i];
for(int i=1;i<=bel[Cmax+D];++i){
for(int j=bel[Cmax+D];j>=1;--j) sum[i][j]+=sum[i][j+1];
}
return ;
}
}cnt;
struct Block1:Block{
inline void prework(){
for(int i=n;i>=1;--i){
int j=i;
while(cor[i].fir==cor[j].fir&&j) --j;
++j;
for(int k=i;k>=j;--k) w[k]=T.query(cor[k].sec+1,Cmax);
for(int k=i;k>=j;--k) T.insert(cor[k].sec,1);
i=j;
}
T.clear();
init();
}
inline void solve(){
ll ans=0;
for(int i=1;i<=bel[Cmax+D];++i){
int l=get_block(lef[i]),r=get_block(rig[i]);
if(r0) ans+=w[cur];
}
}
print(ans);
}
}plain1;
struct Block2:Block{
ll all=0;
inline void prework(){
for(int i=1;i<=n;++i){
int j=i;
while(cor[i].fir==cor[j].fir&&j<=n) ++j;
--j;
for(int k=i;k<=j;++k) w[k]=T.query(-Cmax,cor[k].sec-1);
for(int k=i;k<=j;++k) T.insert(cor[k].sec,1);
i=j;
}
rep(i,1,n) all+=w[i];
T.clear();
init();
}
inline void solve(){
ll ans=all;
for(int i=1;i<=bel[Cmax+D];++i){
int l=get_block(lef[i]),r=get_block(rig[i]);
if(r0) ans+=w[cur],num++;
}
}
print(num*(num-1)/2-ans);
}
}plain3;
struct Block4:Block{
ll all=0;
inline void prework(){
for(int i=n;i>=1;--i){
int j=i;
while(cor[i].fir==cor[j].fir&&j) --j;
++j;
for(int k=j;k<=i;++k) w[k]=T.query(-Cmax,cor[k].sec),T.insert(cor[k].sec,1);
i=j;
}
rep(i,1,n) all+=w[i];
T.clear();
init();
}
inline void solve(){
ll ans=all,num=n;
for(int i=1;i<=bel[Cmax+D];++i){
int l=get_block(lef[i]),r=get_block(rig[i]);
if(r0) plain1.solve();
else plain2.solve();
}else{
if(B>0) plain3.solve();
else plain4.solve();
}
}
}
return 0;
}