1.CF702E Analysis of Pathes in Functional Graph
题意:有一个 n n n 个点 n n n 条边的带权有向图(点编号 0 0 0 ~ n − 1 n-1 n−1),每个点有且仅有一条出边,对于每个点 i i i求出由 i i i出发经过 k k k条边,这 k k k条边的权值最小值和权值和。
思路:倍增
由于k太巨大,硬跑是肯定不行的,然后每个点有且仅有一条出边,所以可以用倍增(
预处理的方式跟ST表差不多
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
int mm[maxn][40],f[maxn][40],son[maxn][40],n,m,k;
inline void query(int i){
int ans=0;
int res=k;
int x=1e18;
for(int j=36;j>=0;j--){
if((1ll<<j)<=res){
res-=(1ll<<j);
ans+=f[i][j];
x=min(x,mm[i][j]);
i=son[i][j];
}
}
printf("%lld %lld\n",ans,x);
}
signed main(){
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>son[i][0];
}
for(int i=0;i<n;i++){
cin>>f[i][0];
mm[i][0]=f[i][0];
}
for(int j=1;j<=36;j++){
for(int i=0;i<n;i++){
son[i][j]=son[son[i][j-1]][j-1];
f[i][j]=f[i][j-1]+f[son[i][j-1]][j-1];
mm[i][j]=min(mm[i][j-1],mm[son[i][j-1]][j-1]);
}
}
for(int i=0;i<n;i++){
query(i);
}
}
2.CF242D Dispute
题意:题意:有 n n n 个计数器和 m m m 条电线,每个计数器都对应着一个额定值 a i a_i ai ,初始时所有计数器的值均为 0 0 0 ,现在你可以按若干个计数器上的按钮,每次按按钮可以使该计数器以及与该计数器通过电线相连的计数器的值都 + 1 +1 +1 ,每个计数器最多只能按一次。当你进行这样的操作若干次后,若有一个计数器上的值与该计数器的额定值一样,你就失败了。需要输出任意一种方案使你可以获胜。若无法获胜,输出 − 1 -1 −1。
思路:bfs
先把额定值为0的点丢进队列,然后跑bfs,最后再遍历一次判断一下是否合法
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
int n,m,k,cnt,a[maxn],now[maxn],vis[maxn];
vector<int>e[maxn],jl;
void bfs(){
queue<int>q;
for(int i=1;i<=n;i++){
if(!a[i])q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
if(now[u]!=a[u])continue;
now[u]++;
jl.push_back(u);
cnt++;
vis[u]=1;
for(auto v:e[u]){
now[v]++;
if(now[v]==a[v]&&!vis[v]){
q.push(v);
}
}
}
for(int i=1;i<=n;i++){
if(now[i]==a[i]){
puts("-1");
return;
}
}
cout<<cnt<<endl;
for(auto x:jl){
cout<<x<<" ";
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;i++)cin>>a[i];
bfs();
}
3.CF229C Triangles
题意:给定n(1<=n<=10 6) 个点组成的完全图,现在从原图中拿走m(0<=m<=106)条边到另一个平面上,问一共还能组成多少个三角形。
思路:正面算两个图中有多少三角形肯定是不行的,逆向思维
先计算出整张图一共有多少个三角形
标记每个点有多少条被取走的边,被取走的边*剩余的边=被破坏的三角形个数
每个被破坏的三角形会属于两个点,要/2
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
int n,m,du[maxn];
signed main(){
cin>>n>>m;
int ans=n*(n-1)/2*(n-2)/3;
for(int i=1;i<=m;i++){
int u,v;
scanf("%lld%lld",&u,&v);
du[u]++;
du[v]++;
}
int d=0;
for(int i=1;i<=n;i++)d+=du[i]*(n-1-du[i]);
cout<<ans-d/2;
}
咕咕咕了