noip模拟38

\(\color{white}{\mathbb{深秋总有廖落处,雁归每是菊败时,名之以:残菊}}\)


pic.png

这场比赛几乎全场都在打暴力,几乎人均切掉的 \(t1\) 没有想到双指针,\(t3\) 的暴力也没记忆化而太过暴力


A. a

很容易想到同时枚举两行,然后算列的贡献

考场上只想到用数状数组维护,但是很显然 \(down\)\(up\) 两条线之间区域的边界是单调的,双指针维护即可


B.b

考虑对于每个 \(i\) 计算 \(i|gcd\) 的方案数,设每一组是 \(i\) 的倍数的数有 \(cnt_j\) 个,答案为 \(\prod (cnt_j+1)-1\)

但是此时每个 \(i\) 保存的是其所有倍数的值之和,那么考虑倒序枚举所有数,其实大于当前数的所有数已经还原成 \(i=gcd\) 的值,那么用当前数的值减去所有倍数的值即可


C.c

一开始没看见去重后是棵树……

首先每条边都有多种候选颜色,但只保留三种即可,即和上一个不重,和下一个不重

考虑点分治,从分治中心开始 \(dp\),设 \(f[i][0/1/2][0/1/2]\) 表示从中心到第 \(i\) 个点,路径上第一条边的颜色为第几种,最后一条边的颜色是第几种的最大价值
然后写棵点分树把询问挂在点分树上的 \(lca\) 就好了

代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxm=1e6+5;
int hd[maxn],cnt,from[maxn],las[maxn],f[maxn][5][5],n,m,q,xx[maxn],yy[maxn],fa[maxn],fa1[maxn],dep[maxn],siz[maxn],rt,maxx[maxn],x,y,w,sum,sta[maxn],tp;
bool del[maxn];
vector<pair<int,int> >has[maxn];
map<pair<int,int>,int>ans,mp;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
struct Edge{
	int nxt,to,val[4];
	int numval;
}edge[maxm];
void add(int u,int v,int w){
	edge[++cnt].nxt=hd[u];
	edge[cnt].to=v;
	edge[cnt].val[++edge[cnt].numval]=w;
	hd[u]=cnt;
	return ;
}
void dfs_w(int u,int father){
	siz[u]=1;
	maxx[u]=0;
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==father||del[v])continue;
		dfs_w(v,u);
		siz[u]+=siz[v];
		maxx[u]=max(maxx[u],siz[v]);
	}
	maxx[u]=max(maxx[u],sum-siz[u]);
	if(maxx[u]<maxx[rt])rt=u;
	return ;
}
void dfs_dis(int u,int father,int last,int num){
//	cout<<u<<" "<<father<<" "<<last<<" "<<num<<endl;
	sta[++tp]=u;
	from[u]=num;
	las[u]=last;
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==father||del[v])continue;
		for(int j=1;j<=edge[num].numval;j++){
			for(int k=1;k<=edge[last].numval;k++){
				for(int p=1;p<=edge[i].numval;p++){
					f[v][j][p]=max(f[v][j][p],f[u][j][k]+(edge[last].val[k]!=edge[i].val[p]));
				}
				
			}
		}
		dfs_dis(v,u,i,num);
	}
	return ;
}
void calc(int u){
//	cout<<u<<endl;
	tp=0;
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(del[v])continue;
		for(int j=1;j<=edge[i].numval;j++)f[v][j][j]=1;
		dfs_dis(v,u,i,i);
	}
	
	for(int i=0;i<has[u].size();i++){
		int x=has[u][i].first,y=has[u][i].second,mx=0;
//		if(u==4)cout<<x<<" "<<y<<endl;
		if(y==u)swap(x,y);
		if(x==u){
			for(int j=1;j<=edge[from[y]].numval;j++){
				for(int k=1;k<=edge[las[y]].numval;k++){
					mx=max(mx,f[y][j][k]);
				}
			}
			ans[has[u][i]]=mx;
			continue;
		}
		for(int j=1;j<=edge[from[x]].numval;j++){
			for(int k=1;k<=edge[from[y]].numval;k++){
				for(int l=1;l<=edge[las[x]].numval;l++){
					for(int r=1;r<=edge[las[y]].numval;r++){
						mx=max(mx,f[x][j][l]+f[y][k][r]-(edge[from[x]].val[j]==edge[from[y]].val[k]));
					}
				}
			}
		}
		ans[has[u][i]]=mx;
	}
//	for(int i=1;i<=tp;i++)cout<<sta[i]<<" ";
//	cout<<endl;
	for(int i=1;i<=tp;i++){
		for(int j=1;j<=3;j++){
			for(int k=1;k<=3;k++){
//				if(u==4)cout<<sta[i]<<" "<<edge[from[sta[i]]].val[j]<<" "<<edge[las[sta[i]]].val[k]<<" "<<f[sta[i]][j][k]<<endl;
				f[sta[i]][j][k]=0;
			}
		}
	}
	return ;
}
void solve(int u){
//	cout<<" "<<u<<endl;
	del[u]=true;
	calc(u);
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(del[v])continue;
		rt=0;
		maxx[rt]=sum=siz[v];
		dfs_w(v,u);
		solve(rt);
	}
	return ;
}
void solve0(int u){
//	cout<<u<<endl;
	del[u]=true;
//	calc(u);
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(del[v])continue;
		rt=0;
		maxx[rt]=sum=siz[v];
		dfs_w(v,u);
		fa1[rt]=u;
		dep[rt]=dep[u]+1;
		solve0(rt);
	}
	return ;
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]!=dep[y]){
		x=fa1[x];
	}
	while(x!=y){
		x=fa1[x];
		y=fa1[y];
	}
	return x;
}
int main(){
//	freopen("c0_1.in","r",stdin);
	n=read();
	m=read();
//	memset(f,-1,sizeof f);
	for(int i=1;i<=m;i++){
		x=read();
		y=read();
		w=read();
		if(mp.find(make_pair(x,y))==mp.end())mp[make_pair(x,y)]=mp[make_pair(y,x)]=cnt+1,add(x,y,w),add(y,x,w);
		else{
			int id=mp[make_pair(x,y)];
			if(edge[id].numval<=2&&edge[id].val[1]!=w&&edge[id].val[2]!=w){
				edge[id].val[++edge[id].numval]=w;
			}
			id++;
			if(edge[id].numval<=2&&edge[id].val[1]!=w&&edge[id].val[2]!=w){
				edge[id].val[++edge[id].numval]=w;
			}
		}
	}
//	for(int i=1;i<=cnt;i+=2){
//		cout<<edge[i].to<<" "<<edge[i+1].to<<" "<<edge[i].val[1]<<" "<<edge[i].val[2]<<" "<<edge[i].val[3]<<endl;
//	}
	maxx[rt]=sum=n;
	dfs_w(1,0);
//	cout<<"ppp "<<rt<<endl;
	solve0(rt);
//	for(int i=1;i<=n;i++){
//		cout<<fa1[i]<<" ";
//	}
	q=read();
	for(int i=1;i<=q;i++){
		xx[i]=read();
		yy[i]=read();
//		cout<<"  "<<lca(xx[i],yy[i])<<endl;
		has[lca(xx[i],yy[i])].push_back(make_pair(xx[i],yy[i]));
	}
	memset(del,0,sizeof del);
	memset(maxx,0,sizeof maxx);
	memset(siz,0,sizeof siz);
	rt=0;
//	cout<<"hhh"<<endl;
	maxx[rt]=sum=n;
	dfs_w(1,0);
	solve(rt);
	for(int i=1;i<=q;i++){
		printf("%d\n",ans[make_pair(xx[i],yy[i])]);
	}
	return 0;
}

\(\color{white}{\mathbb{不是花中偏爱菊,此花开尽更无花。}}\)

posted @ 2021-08-14 17:10  y_cx  阅读(49)  评论(0编辑  收藏  举报