【2020省选模拟】题解

T1:

直接开每个颜色开一个线段树维护直径,再对颜色开颗线段树即可

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin

namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob==(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=100005;
char xxx;
int in[N],dfn,st[19][N<<1],dep[N],fa[N],lg[N<<1];
int adj[N],nxt[N<<1],to[N<<1],ecnt;
void addedge(int u,int v){
	nxt[++ecnt]=adj[u],adj[u]=ecnt,to[ecnt]=v;
}
inline int MIN(int x,int y){return in[x]<in[y]?x:y;}
inline int Lca(int x,int y){
	x=in[x],y=in[y];
	if(x>y)swap(x,y);
	int t=lg[y-x+1];
	return MIN(st[t][x],st[t][y-(1<<t)+1]);
}
inline int dis(int x,int y){
//	assert(x!=0),assert(y!=0); 	
	return dep[x]+dep[y]-2*dep[Lca(x,y)];
}
void dfs(int u){
	st[0][++dfn]=u,in[u]=dfn;
	for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa[u]){
		fa[v]=u,dep[v]=dep[u]+1,dfs(v);
		st[0][++dfn]=u;
	}
}
void buildst(){
	for(int i=2;i<=dfn;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;(1<<i)<=dfn;i++)
	for(int j=1;j+(1<<i)-1<=dfn;j++)
	st[i][j]=MIN(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
struct node{
	int x,y;
	node(int _x=0,int _y=0):x(_x),y(_y){}
	friend inline node operator +(cs node &a,cs node &b){
		if(!a.x)return b;if(!b.x)return a;int mx=-1,t,t1=0,t2=0;
		if((t=dis(a.x,a.y))>mx)mx=t,t1=a.x,t2=a.y;
		if((t=dis(a.x,b.x))>mx)mx=t,t1=a.x,t2=b.x;
		if((t=dis(a.x,b.y))>mx)mx=t,t1=a.x,t2=b.y;
		if((t=dis(a.y,b.x))>mx)mx=t,t1=a.y,t2=b.x;
		if((t=dis(a.y,b.y))>mx)mx=t,t1=a.y,t2=b.y;
		if((t=dis(b.x,b.y))>mx)mx=t,t1=b.x,t2=b.y;
		assert(mx>=0);
		return node(t1,t2);
	}
};
int n,m,q,rt[N];
namespace seg2{
	#define mid ((l+r)>>1)
	cs int N=::N*50;
	node s[N];int lc[N],rc[N],tot;
	void insert(int &u,int l,int r,int p){
		if(!u)u=++tot;
		if(l==r){
			s[u]=node(p,p);return;
		}
		if(p<=mid)insert(lc[u],l,mid,p);
		else insert(rc[u],mid+1,r,p);
		s[u]=s[lc[u]]+s[rc[u]];
	}
	void delet(int &u,int l,int r,int p){
		if(l==r){s[u]=node(0,0);return;}
		if(p<=mid)delet(lc[u],l,mid,p);
		else delet(rc[u],mid+1,r,p);
		s[u]=s[lc[u]]+s[rc[u]];
	}
	#undef mid
}
namespace seg1{
	node s[N<<2];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	void build(int u,int l,int r){
		if(l==r){
			s[u]=seg2::s[rt[l]];
			return;
		}build(lc,l,mid),build(rc,mid+1,r);
		s[u]=s[lc]+s[rc];
	}
	void update(int u,int l,int r,int p,int k,int kd){
		if(l==r){
			if(kd==0)seg2::delet(rt[l],1,n,k);
			else seg2::insert(rt[l],1,n,k);
			s[u]=seg2::s[rt[l]];return;
		}
		if(p<=mid)update(lc,l,mid,p,k,kd);
		else update(rc,mid+1,r,p,k,kd);
		s[u]=s[lc]+s[rc];
	}
	node query(int u,int l,int r,int st,int des){
		if(st<=l&&r<=des)return s[u];
		if(des<=mid)return query(lc,l,mid,st,des);
		if(mid<st)return query(rc,mid+1,r,st,des);
		return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
	}
	#undef lc
	#undef rc
	#undef mid
}
char yyy;
int col[N];
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;i++)col[i]=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}dep[1]=1,dfs(1),buildst();
	for(int i=1;i<=n;i++)seg2::insert(rt[col[i]],1,n,i);
	seg1::build(1,1,m);
	for(int i=1;i<=q;i++){
		int op=read(),x=read(),y=read();
		if(op==1){
			seg1::update(1,1,m,col[x],x,0);
			col[x]=y;
			seg1::update(1,1,m,col[x],x,1);
		}
		else{
			node f=seg1::query(1,1,m,x,y);
			if(!f.x)cout<<0<<'\n';
			else cout<<dis(f.x,f.y)<<'\n';
		}
	}return 0;
}

T2:

首先可以发现 s g sg sg就是 m a x d e p maxdep maxdep
首先我的垃圾做法是考虑提出直径,然后大力分类讨论

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin

namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}
using IO::read;

template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=2e5+5;
char xxx;
inline pii operator ^(cs pii &a,cs pii &b){return pii(a.fi^b.fi,a.se^b.se);}
struct Seg{
	int n,coef[N<<2],tag[N<<2],s[N<<2];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	void build(int u,int l,int r,int *vl){
		if(l==r){tag[u]=1,s[u]=coef[u]=vl[l];return;}
		build(lc,l,mid,vl),build(rc,mid+1,r,vl);
		s[u]=coef[u]=coef[lc]^coef[rc];
	}
	void init(int _n,int *vl){
		n=_n;
		if(!n)return;
		build(1,1,n,vl);
	}
	int st,des;
	void upd(int u,int l,int r){
		if(st<=l&&r<=des){tag[u]^=1;s[u]^=coef[u];return;}
		if(st<=mid)upd(lc,l,mid);
		if(mid<des)upd(rc,mid+1,r);
		s[u]=s[lc]^s[rc]^(tag[u]?coef[u]:0);
	}
	void update(int l,int r){if(!n)return;
		st=l,des=r;upd(1,1,n);
	}
	pii qy(int u,int l,int r){
		if(st<=l&&r<=des)return pii(s[u],coef[u]);
		pii now;
		if(st<=mid)now=now^qy(lc,l,mid);
		if(mid<des)now=now^qy(rc,mid+1,r);
		if(tag[u])now.fi^=now.se;return now;
	}
	int query(int l,int r){if(!n)return 0;
		st=l,des=r;pii x=qy(1,1,n);
		return x.fi;
	}
	int fin(int u,int l,int r,int p){
		if(l==r)return tag[u];
		if(p<=mid)return fin(lc,l,mid,p)^tag[u];
		return fin(rc,mid+1,r,p)^tag[u];
	}
	int find(int p){
		if(!n)return 0;
		return fin(1,1,n,p);
	}
	#undef lc
	#undef rc
	#undef mid
}c1,c2,t1,t2;
// c1->left c2->right t1->sub t2->other
int up[N],rt[N],isc[N],a[N],nrt,n,m;
int chain[N],len,mxlen[N],mxup[N];
int dep[N],fa[N],top[N],in[N],out[N],siz[N],son[N],idx[N],dfn;
int adj[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
	nxt[++ecnt]=adj[u],adj[u]=ecnt,to[ecnt]=v;
}
int dfs(int u,int udep,int urt,int rtt){
	up[u]=urt,rt[u]=rtt,mxup[u]=udep,siz[u]=1;
	for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa[u]){
		if(isc[v])continue;
		fa[v]=u,dep[v]=dep[u]+1;
		chemx(mxlen[u],dfs(v,udep+1,urt,rtt)+1);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}return mxlen[u];
}
void dfs2(int u,int tp){
	top[u]=tp;in[u]=++dfn,idx[dfn]=u;
	if(son[u])dfs2(son[u],tp);
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa[u]||v==son[u]||isc[v])continue;
		dfs2(v,v);
	}out[u]=dfn;
}
int mxdp,mdes,pre[N],mst;
pii qr[N];int cnt;
void updatetree(int l,int r){
	if(l>r)return;
	t1.update(l,r),t2.update(l,r);
}
int find(int u,int p){
	int v=0;
	while(top[u]!=top[p])v=top[u],u=fa[top[u]];
	if(u==p)return v;
	return son[p];
}
void updatechain(int l,int r){
	if(l>r)return;
	c1.update(l,r),c2.update(l,r);
}
void updatepath(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		updatetree(in[top[u]],in[u]);
		u=fa[top[u]];
	}if(dep[u]>dep[v])swap(u,v);
	updatetree(in[u],in[v]);
}
int get(int u){
	cnt=0;
	while(u){
		qr[++cnt]=pii(in[top[u]],in[u]);
		u=fa[top[u]];
	}
	reverse(qr+1,qr+cnt+1);
	int res=0;
	for(int i=1;i<=cnt;i++){
		res^=t2.query(qr[i].fi,qr[i].se);
		if(qr[i-1].se+1<=qr[i].fi-1)res^=t1.query(qr[i-1].se+1,qr[i].fi-1);
	}
	if(qr[cnt].se<dfn)res^=t1.query(qr[cnt].se+1,dfn);
	return res;
}
void dfss(int u,int fa,int dep){
	if(dep>mxdp)mxdp=dep,mst=u;
	for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=fa){
		dfss(v,u,dep+1);
	}
}
void dfst(int u,int dep){
	if(dep>mxdp)mxdp=dep,mst=u;
	for(int e=adj[u],v;e;e=nxt[e])if((v=to[e])!=pre[u]){
		pre[v]=u,dfst(v,dep+1);
	}
}
char yyy;
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	freopen("my.out","w",stdout);
	#endif
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	dfss(1,0,0),mxdp=0,mdes=mst,dfst(mst,0);
	int u=mst;
	while(u!=mdes){
		chain[++len]=u,u=pre[u];
	}chain[++len]=mdes;
	for(int i=1;i<=len;i++)a[i]=i-1;
	c1.init(len,a);
	for(int i=1;i<=len;i++)a[i]=len-i;
	c2.init(len,a);
	for(int i=1;i<=len;i++)isc[chain[i]]=1;
	for(int i=1;i<=len;i++){int u=chain[i];up[u]=i;
		in[u]=dfn+1;
		for(int e=adj[u],v;e;e=nxt[e])if(!isc[v=to[e]]){
			dfs(v,max(i-1,len-i)+1,i,v),dfs2(v,v);
		}
		out[u]=dfn;
	}
	for(int i=1;i<=dfn;i++)a[i]=mxlen[idx[i]];
	t1.init(dfn,a);
	for(int i=1;i<=dfn;i++)a[i]=mxup[idx[i]];
	t2.init(dfn,a);nrt=1;
	while(m--){
		int op=read();
		if(op==1){
			int u=read(),v=read();
			if(!isc[u]&&!isc[v]&&rt[u]==rt[v]){
				updatepath(u,v);
			}
			else{
				if(!isc[u])updatepath(u,rt[u]);
				if(!isc[v])updatepath(v,rt[v]);
				updatechain(min(up[u],up[v]),max(up[u],up[v]));
			}
		}
		else{
			int u=read();
			if(u==nrt){
				updatetree(1,dfn),updatechain(1,len);
			}
			else if(!isc[nrt]){
				if(in[u]<=in[nrt]&&in[nrt]<=out[u]&&!isc[u]){
					updatechain(1,len);
					int p=find(nrt,u);
					updatetree(1,in[p]-1);
					updatetree(out[p]+1,dfn);
				}
				else if((in[nrt]<=in[u]&&in[u]<=out[nrt])&&!isc[u]){
					updatetree(in[u],out[u]);
				}
				else if(!isc[u]){
					updatetree(in[u],out[u]);
				}
				else{
					assert(isc[u]);
					int id=up[u];
					if(id==up[nrt]){
						updatechain(1,len);
						updatetree(1,in[rt[nrt]]-1);
						updatetree(out[rt[nrt]]+1,dfn);
					}
					else{
						if(id<up[nrt]){
							updatechain(1,id);
							updatetree(1,out[chain[id]]);
						}
						else{
							updatechain(id,len);
							updatetree(in[chain[id]],dfn);
						}
					}
				}
			}
			else{
				if(!isc[u]){
					updatetree(in[u],out[u]);
				}
				else{
					int id=up[u];
					if(id<up[nrt]){
						updatechain(1,id);
						updatetree(1,out[chain[id]]);
					}
					else{
						updatechain(id,len);
						updatetree(in[chain[id]],dfn);
					}
				}
			}
		}
		int x=read();
		nrt=x;int res=max(up[x]-1,len-up[x])*(c1.find(up[x])&1);
		if(isc[x]){
			res^=t1.query(1,dfn);
			if(up[x]>1)res^=c1.query(1,up[x]-1);
			if(up[x]<len)res^=c2.query(up[x]+1,len);
		}
		
		else{
			res^=get(x);
			if(up[x]>1)res^=c1.query(1,up[x]-1);
			if(up[x]<len)res^=c2.query(up[x]+1,len);			
		}cout<<res<<'\n';
	}
}

s t d std std是考虑直径中点为根
维护两个方向的 m x d e p mxdep mxdep
这样就只是把一条链的权值换一下,树剖即可

仲爺教育我的神仙方法
直接把1作为根
不同的只是1到当前根的路径
只需要重剖时链权值变成重儿子为根的 d e p dep dep
跳轻链的时候另外算一下即可

T3:

考虑设
f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]
表示前 i i i站, j j j轮,每辆车都满,初始人数为 0 / 1 ∗ a i 0/1*a_i 0/1ai的最小车数
g g g表示在 s : 31 s:31 s:31时,除 p p p以外都空的最短车数

考虑上一次接到p的人的时间
如果没有, f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i1][j]
v a l = ⌈ 0 / 1 ∗ s a i − 1 + j ∗ s b i − 1 k ⌉ val=\lceil\frac{0/1*sa_{i-1}+j*sb_{i-1}}{k}\rceil val=k0/1sai1+jsbi1
如果 v a l ∗ k ≤ k ∗ s a i + j ∗ s b i , g [ i ] [ j ] [ k ] = v a l val*k\le k*sa_i+j*sb_i,g[i][j][k]=val valkksai+jsbi,g[i][j][k]=val

如果有,设为 p p p
那么决策是 r r r前有个数量,然后派若干辆保证之后不炸,这次再派若干辆
那么首先派 g [ i ] [ p ] [ k ] g[i][p][k] g[i][p][k],此 p p p i i i m = k ∗ s a i + p ∗ s b i − k ∗ g [ i ] [ p ] [ k ] m=k*sa_i+p*sb_i-k*g[i][p][k] m=ksai+psbikg[i][p][k]
此时需要派 x = ( max ⁡ ( m + ( j − p ) ∗ b i − c i , 0 ) + k − 1 ) / k x=(\max({m+(j-p)*b_i-c_i,0})+k-1)/k x=(max(m+(jp)bici,0)+k1)/k
当然如果 x ∗ k > m x*k>m xk>m,不合法
此时前面都不剩了,且还需要坚持 j − p j-p jp
f [ i ] [ j ] [ k ] = g [ i ] [ p ] [ k ] + x + f [ i − 1 ] [ j − p ] [ 0 ] f[i][j][k]=g[i][p][k]+x+f[i-1][j-p][0] f[i][j][k]=g[i][p][k]+x+f[i1][jp][0]
v l = ( ( j − p ) ∗ s b i − 1 + k − 1 ) / k vl=((j-p)*sb_{i-1}+k-1)/k vl=((jp)sbi1+k1)/k
如果 v l ∗ k ≤ s b i ∗ ( j − p ) + m − x ∗ k vl*k\le sb_i*(j-p)+m-x*k vlksbi(jp)+mxk
那么 g [ i ] [ j ] [ k ] = g [ i ] [ p ] [ k ] + x + v l g[i][j][k]=g[i][p][k]+x+vl g[i][j][k]=g[i][p][k]+x+vl

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin

namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}
using IO::read;

template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=306;
ll f[N][N][2],g[N][N][2],sa[N],sb[N],sc[N],a[N],b[N],c[N];
cs ll inf=1e17;
int n,t,K;
int main(){
	n=read(),t=read(),K=read();
	for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),c[i]=read();
	a[++n]=inf,b[n]=0,c[n]=inf;
	for(int i=1;i<=n;i++)sa[i]=sa[i-1]+a[i],sb[i]=sb[i-1]+b[i],sc[i]=sc[i-1]+c[i];
	for(int i=1;i<=n;i++)memset(f[i],127/3,sizeof(f[i])),memset(g[i],127/3,sizeof(g[i]));
	for(int i=1;i<=n;i++)
	for(int j=0;j<=t;j++)
	for(int k=0;k<2;k++){
		if(f[i-1][j][k]<inf&&a[i]*k+b[i]*j<=c[i]){
			chemn(f[i][j][k],f[i-1][j][k]);
			ll vl=(sa[i-1]*k+sb[i-1]*j+K-1)/K;
			if(vl*K<=sa[i]*k+sb[i]*j)chemn(g[i][j][k],vl);
		}
		for(int p=0;p<j;p++)if(g[i][p][k]<inf){
			ll m=sa[i]*k+p*sb[i]-g[i][p][k]*K,
			x=(max(m+(j-p)*b[i]-c[i],0ll)+K-1)/K;
			if(x*K>m||f[i-1][j-p][0]>=inf)continue;
			chemn(f[i][j][k],g[i][p][k]+x+f[i-1][j-p][0]);
			ll vl=((j-p)*sb[i-1]+K-1)/K;
			if(vl*K<=sb[i]*(j-p)+m-x*k)chemn(g[i][j][k],g[i][p][k]+x+vl);
		}
	}cout<<f[n][t][1]<<'\n';return 0;
}

你可能感兴趣的:(【2020省选模拟】题解)