模拟赛20200229(ay)【max函数分割点、单调队列优化,动态点分治+线段树维护修改边权】

T1:队列

在这里插入图片描述
在这里插入图片描述

题解:

在这里插入图片描述
Code:

#include<bits/stdc++.h>
#define maxn 5005
using namespace std;
int n,w[maxn],f[maxn][maxn],s[maxn],t[maxn],q[maxn][maxn],g;
int main()
{
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=n;i>=1;i--){
		f[i][i]=w[i],g=i,s[0]=1,t[0]=0;
		q[i][s[i]=t[i]=1]=i;
		for(int j=i+1;j<=n;j++){
			while(g<j&&f[i][g-1]<f[g+1][j]) g++;
			while(s[0]<=t[0]&&q[0][s[0]]<g) s[0]++;
			while(s[0]<=t[0]&&f[i][q[0][t[0]]-1]+w[q[0][t[0]]]>f[i][j-1]+w[j]) t[0]--;
			q[0][++t[0]]=j;
			while(s[j]<=t[j]&&q[j][s[j]]>=g) s[j]++;
			while(s[j]<=t[j]&&f[q[j][t[j]]+1][j]+w[q[j][t[j]]]>f[i+1][j]+w[i]) t[j]--;
			q[j][++t[j]]=i;
			f[i][j]=min(f[i][q[0][s[0]]-1]+w[q[0][s[0]]],f[q[j][s[j]]+1][j]+w[q[j][s[j]]]);
		}
	}
	printf("%d\n",f[1][n]);
}

T2:标记

在这里插入图片描述
1 ≤ L ≤ R ≤ 1 0 7 1\le L\le R\le10^7 1LR107

题解:

最小因子 < L <L <L的数是必须被主动标记的,当这些数全部被主动标记的时候游戏就结束了,假设有 k k k个,那么剩下的 n − k n-k nk个就是可选可不选,枚举它们选了几个,统计一下方案数就可以了。
A n s = ∑ i = 0 n − k k ! ∗ A n − k i ∗ C i + k − 1 k − 1 ∗ ( i + k ) Ans=\sum_{i=0}^{n-k}k!*A_{n-k}^i*C_{i+k-1}^{k-1}*(i+k) Ans=i=0nkk!AnkiCi+k1k1(i+k)

Code:

#include<bits/stdc++.h>
#define maxn 10000005
using namespace std;
const int mod = 998244353;
int L,R,n,k,fac[maxn],inv[maxn],ans;
bool vis[maxn];
inline int Pow(int a,int b){
	int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
inline int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
int main()
{
	freopen("mark.in","r",stdin);
	freopen("mark.out","w",stdout);
	scanf("%d%d",&L,&R),n=R-L+1;
	fac[0]=inv[0]=1;
	for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
	inv[n]=Pow(fac[n],mod-2);
	for(int i=n-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=L;i<=R;i++) if(!vis[i]){
		k++;
		for(int j=i;j<=R;j+=i) vis[j]=1;
	}
	for(int i=0;i<=n-k;i++) ans=(ans+1ll*C(n-k,i)*fac[i]%mod*C(i+k-1,k-1)%mod*(i+k))%mod;
	printf("%d\n",1ll*ans*fac[k]%mod);
}

T3:买买买

在这里插入图片描述
在这里插入图片描述

题解:

容易想到动态点分治,需要知道怎么维护修改边权。
在每个点分中心上开一棵线段树,求出它下面的点关于它的dfs序,那么修改一条边对于这个点分中心来说就是修改一棵子树,也就是dfs序上的一段区间。
在这里插入图片描述
Code:

#include<bits/stdc++.h>
#define maxn 100005
#define maxp maxn*40//2nlogn
#define LL long long
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &a){
	char c;while(!isdigit(c=getc()));
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
const LL inf = 1ll<<60;
int n,m,S=1,rt[maxn],ln[maxn],fa[maxn],dep[maxn],dfn[20][maxn],tim,siz[20][maxn];//点分树父亲、点分深度
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
LL dis[maxn],a[maxn],w[maxn<<1];
bool vis[maxn];
map<pair<int,int>,LL>len;
inline void line(int x,int y,LL z){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y,w[tot]=z;}
struct node{
	LL x;int id;
	bool operator < (const node &p)const{return x==p.x?id>p.id:x<p.x;}
}t[maxp];
int lc[maxp],rc[maxp],cnt; LL tag[maxp];
void build(int &i,int l,int r){
	i=++cnt;
	if(l==r) {t[i].x=a[ln[l]]-dis[ln[l]],t[i].id=ln[l];return;}
	int mid=(l+r)>>1;
	build(lc[i],l,mid),build(rc[i],mid+1,r);
	t[i]=max(t[lc[i]],t[rc[i]]);
}
inline void add(int i,LL v){t[i].x+=v,tag[i]+=v;}
inline void pushdown(int i){if(tag[i]) add(lc[i],tag[i]),add(rc[i],tag[i]),tag[i]=0;}
void insert(int i,int l,int r,int x,int y,LL v){
	if(x<=l&&r<=y) {add(i,v);return;}
	pushdown(i);
	int mid=(l+r)>>1;
	if(x<=mid) insert(lc[i],l,mid,x,y,v);
	if(y>mid) insert(rc[i],mid+1,r,x,y,v);
	t[i]=max(t[lc[i]],t[rc[i]]);
}
node query(int i,int l,int r,int x,int y){
	if(x>r||y<l) return (node){-inf,0};
	if(x<=l&&r<=y) return t[i];
	pushdown(i);
	int mid=(l+r)>>1;
	return max(query(lc[i],l,mid,x,y),query(rc[i],mid+1,r,x,y));
}
int getroot(int u,int ff,int tsz,int &g){
	int sz=1,tmp; bool flg=1;
	for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff)
		sz+=(tmp=getroot(v,u,tsz,g)),flg&=tmp<<1<=tsz;
	if(flg&&(tsz-sz)<<1<=tsz) g=u;
	return sz;
}
void dfs(int u,int ff,int d){
	ln[dfn[d][u]=++tim]=u,siz[d][u]=1;
	for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff)
		dis[v]=dis[u]+w[i],dfs(v,u,d),siz[d][u]+=siz[d][v];
}
int TDC(int u,int tsz,int Depth){
	getroot(u,0,tsz,u),vis[u]=1;
	tim=0,dis[u]=0,dfs(u,0,dep[u]=Depth);
	build(rt[u],1,tsz);
	for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]])
		fa[TDC(v,siz[Depth][v],Depth+1)]=u;
	return u;
}
int main()
{
	freopen("buy.in","r",stdin);
	freopen("buy.out","w",stdout);
	int x,y,op; LL z;
	read(n),read(m);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<n;i++){
		read(x),read(y),read(z),line(x,y,z),line(y,x,z);
		if(x>y) swap(x,y); len[make_pair(x,y)]=z;
	}
	TDC(1,n,1);
	while(m--){
		read(op);
		if(op==1){
			read(x),read(z);
			for(int i=x,d;i;i=fa[i]) d=dep[i],insert(rt[i],1,siz[d][i],dfn[d][x],dfn[d][x],z-a[x]);
			a[x]=z;
		}
		else{
			read(x),read(y),read(z); if(x>y) swap(x,y);
			LL delta=z-len[make_pair(x,y)]; len[make_pair(x,y)]=z;
			for(int i=dep[x]<dep[y]?x:y,d;i;i=fa[i]){
				d=dep[i]; if(siz[d][x]>siz[d][y]) swap(x,y);
				insert(rt[i],1,siz[d][i],dfn[d][x],dfn[d][x]+siz[d][x]-1,-delta);
			}
		}
		node ans=(node){-inf,0},ret;
		for(int i=S,d;i;i=fa[i]){
			d=dep[i];
			ret=max(query(rt[i],1,siz[d][i],1,dfn[d][S]-1),query(rt[i],1,siz[d][i],dfn[d][S]+1,siz[d][i]));
			ret.x+=query(rt[i],1,siz[d][i],dfn[d][S],dfn[d][S]).x-a[S];
			ans=max(ans,ret);
		}
		printf("%d\n",S=ans.id);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值