noip模拟38
\(\color{white}{\mathbb{深秋总有廖落处,雁归每是菊败时,名之以:残菊}}\)
这场比赛几乎全场都在打暴力,几乎人均切掉的 \(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{不是花中偏爱菊,此花开尽更无花。}}\)