ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

冲刺国赛7.18

2022-07-24 10:00:57  阅读:149  来源: 互联网

标签:rt ch int top 7.18 冲刺 st 国赛 son


T1

先分类讨论把 \(\max\) 拆开

假设 \(a_c+b_c\geq a_y+b_y\)

\(a_c-a_y\geq b_y-b_c\)

于是对于每个蛋糕都记录一个判据量 \(h\)

属于 \(L\) 的判据为 \(c-y\) 属于 \(C\) 的是 \(y-c\)

当 \(a\) 的判据大于等于 \(b\) 的时候取最小的 \(b_c\)

再开一个关于 \(h\) 值域的线段树,叶子节点用 \(\text{multiset}\) 维护最小的 \(c\) 和 \(y\)

合并时根据判据的大小分别从左右儿子中取 \(c\) 和 \(y\)

在叶子节点时,两个判据相当也可以取最小值

Code
#include<bits/stdc++.h>
#define int long long
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
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;
}
bool mem1;
int n,rt,tot;
int O[2000010],cnt;
int op[1000010],d[1000010],c[1000010],y[1000010],pos[1000010];
struct seg{int mnc[2],mny[2],ans;}st[1000010*4];
multiset<int>s[1000010][2][2];//pos l/c c/y
inline void pushup(int rt){
	st[rt].ans=min(st[lson].ans,st[rson].ans);
	st[rt].ans=min(st[rt].ans,st[lson].mnc[1]+st[rson].mnc[0]);
	st[rt].ans=min(st[rt].ans,st[lson].mny[0]+st[rson].mny[1]);
	st[rt].mnc[0]=min(st[lson].mnc[0],st[rson].mnc[0]);
	st[rt].mny[0]=min(st[lson].mny[0],st[rson].mny[0]);
	st[rt].mnc[1]=min(st[lson].mnc[1],st[rson].mnc[1]);
	st[rt].mny[1]=min(st[lson].mny[1],st[rson].mny[1]);
}
void upd(int rt,int l,int r,int pos,int i){
	if(l==r){
		if(op[i]==1){
			s[l][d[i]][0].insert(c[i]);st[rt].mnc[d[i]]=*s[l][d[i]][0].begin();
			s[l][d[i]][1].insert(y[i]);st[rt].mny[d[i]]=*s[l][d[i]][1].begin();
		}
		if(op[i]==0){
			s[l][d[i]][0].erase(s[l][d[i]][0].find(c[i]));if(!s[l][d[i]][0].empty()) st[rt].mnc[d[i]]=*s[l][d[i]][0].begin();else st[rt].mnc[d[i]]=inf;
			s[l][d[i]][1].erase(s[l][d[i]][1].find(y[i]));if(!s[l][d[i]][1].empty()) st[rt].mny[d[i]]=*s[l][d[i]][1].begin();else st[rt].mny[d[i]]=inf;
		}
		st[rt].ans=min(st[rt].mnc[0]+st[rt].mnc[1],st[rt].mny[0]+st[rt].mny[1]);
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) upd(lson,l,mid,pos,i);
	else upd(rson,mid+1,r,pos,i);
	pushup(rt);
}
bool mem2;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("cake.in","r",stdin);
	freopen("cake.out","w",stdout);
	n=read();memset(st,0x3f,sizeof(st));
	for(int i=1;i<=n;i++){
		op[i]=read(),d[i]=read(),c[i]=read(),y[i]=read();
		if(d[i]==0) O[++cnt]=pos[i]=c[i]-y[i];
		if(d[i]==1) O[++cnt]=pos[i]=y[i]-c[i];
	}
	sort(O+1,O+1+cnt);cnt=unique(O+1,O+1+cnt)-O-1;
	for(int i=1;i<=n;i++) pos[i]=lower_bound(O+1,O+1+cnt,pos[i])-O;
	for(int i=1;i<=n;i++){
		upd(1,1,cnt,pos[i],i);
		printf("%lld\n",st[1].ans<=2000000000?st[1].ans:-1ll);
	}	
	return 0;
}

T2

一行一行的转移,设 \(f_i=[i\in S]\)

发现如果 \(b\) 只有一种转移

那就是普通的位运算卷积

现在有很多种 \(b\) 发现每一位和每一位之间是不影响的

所以可以按位考虑,根据当前位的 \(b\) 去做 \(\text{fwt}\)

然后行与行之间的转移都是相同的,于是再做个快速幂

Code
#include<bits/stdc++.h>
#define int long long
#define i2 500000004
#define mod 1000000007
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
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,m,q,len;
int a[1048576],b[1048576];
char s[1048576];
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline void fwt(int tx){
	for(int d=1,bit=0;d<len;d<<=1,bit++) for(int i=0;i<len;i+=d<<1) for(int j=0;j<d;j++){
		int x=a[i+j],y=a[i+j+d];
		if(b[bit]==1) (a[i+j+d]+=a[i+j]*tx)%=mod;
		if(b[bit]==2) (a[i+j]+=a[i+j+d]*tx)%=mod;
		if(b[bit]==3){
			a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
			if(tx==mod-1) a[i+j]=a[i+j]*i2%mod,a[i+j+d]=a[i+j+d]*i2%mod;
		}
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("completion.in","r",stdin);
	freopen("completion.out","w",stdout);

	n=read(),m=read();scanf("%s",s);len=1<<m;
	for(int i=0;i<m;i++) b[i]=read();
	for(int i=0;i<len;i++) a[i]=s[i]-'0';
	
	fwt(1);
	for(int i=0;i<len;i++) a[i]=qpow(a[i],n);
	fwt(mod-1);
	
	q=read();
	for(int i=1;i<=q;i++) printf("%lld\n",a[read()]);
	return 0;
}

T3

找两个前缀的最长后缀,可以用 \(\text{SAM}\)

直接找他们两个前缀代表的节点在 \(\text{parent}\) 树上的 \(\text{LCA}\) 就是他们的最长后缀

现在要找的就是两两之间的最长前缀,可以把这些节点代表的串建出 \(\text{Trie}\)

然后最长前缀的长度就是 \(\text{LCA}\) 的深度,然后就变成了一个经典问题,可以用树剖做

现在瓶颈在于建 \(\text{Trie}\)

发现这颗 \(\text{Trie}\) 的节点很少,且和 \(\text{SAM}\) 上的节点一一对应

于是直接枚举 \(\text{SAM}\) 上的每条边,如果两个节点代表的长度正好差 \(1\) 就说明是 \(\text{Trie}\) 上的边

Code
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
#define meow(args...) fprintf(stderr,args)
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,tot=1,lst=1,ans;
int pos[500010];
char s[500010];
bool vis[1000010];
namespace Trie{
	int c1[1000010],c2[1000010];
	int fa[1000010],son[1000010],dep[1000010],siz[1000010],top[1000010],dfn[1000010],clo;
	int head[1000010],ver[1000010],to[1000010],cnt;
	inline void add(int x,int y){
		ver[++cnt]=y;to[cnt]=head[x];head[x]=cnt;
	}
	inline void ins(int l,int r,int k){
		for(int w=(l-1)*k;l<=tot;l+=l&-l) c1[l]+=k,c2[l]+=w;r++;
		for(int w=(r-1)*k;r<=tot;r+=r&-r) c1[r]-=k,c2[r]-=w;
	}
	inline int query(int l,int r){
		int res=0;
		for(int w=r;r;r-=r&-r) res+=c1[r]*w-c2[r];l--;
		for(int w=l;l;l-=l&-l) res-=c1[l]*w-c2[l];
		return res;
	}
	void dfs1(int x,int fath,int depth){
		fa[x]=fath,dep[x]=depth,siz[x]=1;
		int maxson=-1;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];dfs1(y,x,depth+1);
			siz[x]+=siz[y];
			if(siz[y]>maxson) maxson=siz[y],son[x]=y;
		}
	}
	void dfs2(int x,int topf){
		dfn[x]=++clo;
		top[x]=topf;if(!son[x]) return;
		dfs2(son[x],topf);
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];if(y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline void upd(int x,int k){
		while(top[x]!=1) ins(dfn[top[x]],dfn[x],k),x=fa[top[x]];
		if(dfn[x]>1) ins(dfn[1]+1,dfn[x],k);
	}
	inline int query(int x){
		int res=0;
		while(top[x]!=1) res+=query(dfn[top[x]],dfn[x]),x=fa[top[x]];
		res+=query(dfn[1],dfn[x]);
		return res;
	}
}
namespace SAM{
	struct node{int len,fa,son[4];}t[1000010];
	int fa[1000010],son[1000010],dep[1000010],siz[1000010],top[1000010];
	int head[1000010],ver[1000010],to[1000010],cnt;
	inline void add(int x,int y){
		ver[++cnt]=y;to[cnt]=head[x];head[x]=cnt;
	}
	inline void extend(int c,int u){
		int p=++tot,f=lst;lst=p;
		t[p].len=t[f].len+1;pos[u]=p;
		while(f&&!t[f].son[c]) t[f].son[c]=p,f=t[f].fa;
		if(!f) return t[p].fa=1,void();
		int x=t[f].son[c],y=++tot;
		if(t[f].len+1==t[x].len) return tot--,t[p].fa=x,void();
		t[y]=t[x];t[y].len=t[f].len+1,t[x].fa=t[p].fa=y;
		while(f&&t[f].son[c]==x) t[f].son[c]=y,f=t[f].fa;
	}
	void dfs1(int x,int fath,int depth){
		fa[x]=fath,dep[x]=depth,siz[x]=1;
		int maxson=-1;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];dfs1(y,x,depth+1);
			siz[x]+=siz[y];
			if(siz[y]>maxson) maxson=siz[y],son[x]=y;
		}
	}
	void dfs2(int x,int topf){
		top[x]=topf;if(!son[x]) return;
		dfs2(son[x],topf);
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];if(y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline int LCA(int x,int y){
		while(top[x]!=top[y]) (dep[top[x]]>dep[top[y]])?x=fa[top[x]]:y=fa[top[y]];
		return (dep[x]<dep[y])?x:y;
	}
	void build(){
		for(int i=2;i<=tot;i++) add(t[i].fa,i);
		for(int i=1;i<=tot;i++) for(int j=0;j<4;j++) if(t[i].son[j]) if(t[i].len+1==t[t[i].son[j]].len) Trie::add(i,t[i].son[j]);
		dfs1(1,0,1);dfs2(1,1);Trie::dfs1(1,0,1);Trie::dfs2(1,1);
		
		// for(int i=1;i<=tot;i++) printf("t[%lld].len : %lld\n",i,t[i].len);
		// for(int i=1;i<=tot;i++) for(int j=0;j<4;j++) if(t[i].son[j]) printf("%lld -> %lld\n",i,t[i].son[j]);
		// for(int i=1;i<=n;i++) printf("pos[%lld] : %lld\n",i,pos[i]);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("elixir.in","r",stdin);
	freopen("elixir.out","w",stdout);
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++) SAM::extend(s[i]-'a',i);SAM::build();
	q=read();
	for(int i=1,x,y,z;i<=q;i++){
		x=pos[read()],y=pos[read()];
		z=SAM::LCA(x,y);
		if(vis[z]){
			vis[z]=0,Trie::upd(z,-1),ans-=Trie::query(z);
		}else{
			vis[z]=1,ans+=Trie::query(z),Trie::upd(z, 1);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

标签:rt,ch,int,top,7.18,冲刺,st,国赛,son
来源: https://www.cnblogs.com/MaxQAQ/p/16491369.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有