WY模拟赛11
WY模拟赛11
T1. 洛谷 P4427 [BJOI2018] 求和 S
预处理 $ k $ 次方和和倍增信息,然后 $ LCA $ 求解答案即可。
code:
#include <bits/stdc++.h>
#define i8 __int128
// #define int long long
#define fuck inline
#define lb long double
using namespace std;
typedef long long ll;
const int N=3e5+5,M=9e6+5,mod=998244353;
const int INF=1e9+7;
const ll inf=LONG_LONG_MAX/4;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
fuck int ksm(int a,int b)
{
int res=1;
while(b)
{
// cout<<res<<" "<<a<<" "<<b<<endl;
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res%mod;
}
int n,m;
vector<int>g[N];
int vis[N];
int dep[N],f[N][23];
fuck void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;f[u][0]=fa;
for(auto v:g[u])
{
if(v==fa)continue;
dfs(v,u);
}
}
fuck int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int cha=dep[x]-dep[y];
for(int i=20;i>=0;i--)
{
if(cha&(1<<i))x=f[x][i];
}
// cout<<x<<" "<<y<<"\n";
if(x==y)return x;
for(int i=20;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int frz[55][N],sum[55][N];
fuck void pre()
{
for(int k=1;k<=50;k++)
for(int i=1;i<=n;i++)frz[k][i]=ksm(i,k)%mod;
for(int k=1;k<=50;k++)
for(int i=1;i<=n;i++)sum[k][i]=((ll)sum[k][i-1]+(ll)frz[k][i])%mod;
}
fuck void solve()
{
// cout<<ksm(2,45)%mod<<endl;
n=read();
pre();
// for(int k=45;k<=45;k++)
// {
// for(int i=1;i<=n;i++)cout<<sum[k][i]<<" ";
// cout<<endl;
// }
for(int i=1;i<=n-1;i++)
{
int x,y;x=read(),y=read();
g[x].push_back(y);g[y].push_back(x);
}
dep[0]=-1;
dfs(1,0);
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
{
f[j][i]=f[f[j][i-1]][i-1];
}
m=read();
while(m--)
{
int x,y,k;x=read(),y=read(),k=read();
int fu=lca(x,y);
// cout<<dep[x]<<" "<<dep[y]<<" "<<dep[fu]<<endl;
// cout<<sum[45][2]<<"\n"<<sum[45][1]<<"\n";
ll ans=((ll)sum[k][dep[y]]-(ll)sum[k][max(0,dep[fu]-1)]+mod)%mod;
ans=(ans+(ll)sum[k][dep[x]]-(ll)sum[k][max(0,dep[fu]-1)]+mod)%mod;
ans=(ans+mod-frz[k][dep[fu]])%mod;
cout<<ans<<"\n";
}
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int QwQ=read();
// int fuckccf=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T2. 洛谷 P12007 【MX-X10-T3】[LSOT-4] 全国联赛?
这绿题是真的有点恶心。
我们需要向一个森林中加一些固定边权的边来得到一棵树,要树上两点间距离和最小。考虑合并两棵带权树的重心,把一个联通的带权树看成一个点,要求距离最小肯定是个菊花,只需要把最大的树放在菊花图的中心,次大的用最小的边连接,最小的用最长的边连接即可,换根 $ DP $ 求重心。
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=1e6+5,M=64,mod=1e9+7;
const int INF=1e9+7,inv2=5e8+4;
const int inf=LONG_LONG_MAX/4;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int vis[N];
int sz[N];
int f[N];
int a[N];
int ans,zx;
int n,m;
vector<pair<int,int> >g[N];
#define fr first
#define se second
fuck void dfs1(int u,int fa)
{
sz[u]=1;
for(auto v:g[u])
{
if(v.fr==fa)continue;
dfs1(v.fr,u);
sz[u]+=sz[v.fr];
f[u]+=sz[v.fr]*v.se%mod+f[v.fr];
}
}
fuck void dfs2(int u,int fa)
{
zx=min(zx,f[u]);
for(auto v:g[u])
{
if(v.fr==fa)continue;
ans+=sz[v.fr]*(sz[u]-sz[v.fr])%mod*v.se%mod;
ans%=mod;
f[v.fr]+=(f[u]-f[v.fr]-sz[v.fr]*v.se+(sz[u]-sz[v.fr])*v.se);
sz[v.fr]=sz[u];
dfs2(v.fr,u);
}
}
fuck void solve()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v,w;cin>>u>>v>>w;
g[u].push_back({v,w});
g[v].push_back({u,w});
}
vector<int>v;
for(int i=1;i<=n;i++)
{
if(!sz[i])
{
zx=0x7f7f7f7f7f7f7f7f;
dfs1(i,0);
dfs2(i,0);
zx%=mod;
ans+=zx*(n-sz[i]);
ans%=mod;
v.push_back(sz[i]);
}
}
sort(v.begin(),v.end());
for(int i=1;i<=n-1-m;i++)cin>>a[i];
sort(a+1,a+n-m,greater<int>());
for(int i=1;i<=n-m-1;i++)
{
ans+=a[i]*v[i-1]%mod*(n-v[i-1])%mod;
ans%=mod;
}
cout<<(ans+mod)%mod<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int QwQ=read();
// int fuckccf=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T3. 洛谷 P9233 [蓝桥杯 2023 省 A] 颜色平衡树
树上启发式合并的板子,动态计算并 $ check $ 节点。
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=2e5+5,M=64,mod=998244353;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,cmax=0;
int c[N],gson[N],sz[N];
vector<int>g[N];
fuck void dfs(int u,int fa)
{
sz[u]=1;
for(auto v:g[u])
{
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[gson[u]])gson[u]=v;
}
}
int frz=0,ans=0,sum[N],ssum[N];
fuck void calc(int u,int fa,int op)
{
if(op==1)
{
--ssum[sum[c[u]]];
sum[c[u]]++;
++ssum[sum[c[u]]];
}
else
{
--ssum[sum[c[u]]];
sum[c[u]]--;
++ssum[sum[c[u]]];
}
for(auto v:g[u])
{
if(v==fa||v==frz)continue;
calc(v,u,op);
}
}
fuck void dsu(int u,int fa,int op)
{
for(auto v:g[u])
{
if(v==fa||v==gson[u])continue;
dsu(v,u,0);
}
if(gson[u])dsu(gson[u],u,1),frz=gson[u];
calc(u,fa,1);
frz=0;
if(sum[c[u]]*ssum[sum[c[u]]]==sz[u])ans++;//个人感觉挺妙的
if(!op)calc(u,fa,-1);
}
fuck void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int dad,color;cin>>color>>dad;
c[i]=color;
if(dad)g[dad].push_back(i);
}
// for(int i=1;i<=n;i++)cout<<gson[i]<<"\n";
dfs(1,0);
dsu(1,0,0);
cout<<ans<<"\n";
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
T4. 洛谷 P11562 【MX-X7-T3】[LSOT-3] 寄存器
非常奇妙的类似缩点的操作,最后全都转化为 $ 01 $ 间隔的情况处理。
code:
#include <bits/stdc++.h>
#define i8 __int128
#define int long long
#define fuck inline
#define lb long double
using namespace std;
// typedef long long ll;
const int N=2e6+5,M=64,mod=998244353;
const int inf=INT_MAX,INF=1e9+7;
// const int mod1=469762049,mod2=998244353,mod3=1004535809;
// const int G=3,Gi=332748118;
// const int M=mod1*mod2;
fuck int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
return x*f;
}
fuck void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,dis[N],a[N];
vector<int>g[N];
fuck void dfs(int u,int fa)
{
dis[u]=dis[fa]+(a[u]!=a[fa]);
for(auto v:g[u])
{
if(v==fa)continue;
dfs(v,u);
}
}
fuck void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++)
{
int x,y;cin>>x>>y;
g[x].push_back(y);g[y].push_back(x);
}
int id=0;
dfs(1,0);
for(int i=1;i<=n;i++)if(dis[i]>dis[id])id=i;
dfs(id,0);
for(int i=1;i<=n;i++)if(dis[i]>dis[id])id=i;
cout<<((dis[id]+1)>>1);
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
// int fuckccf=read();
// int QwQ=read();
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
总结
- 训练算法板子;
- 提高思维能力;
- 总结题目套路。
完结收工!!!!!

看完点赞,养成习惯
\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)

浙公网安备 33010602011771号