【图论基础题】

【图论基础题】

哎哎全是结论题大佬呜呜呜啊啊啊呜呜呜
画图可得

Tree Jumps

https://codeforces.com/contest/2070/problem/D

思路

考虑单点贡献为上一层的贡献扣掉父节点贡献
最后将全部结点贡献相加即可

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=300001;
const ll mod=998244353;
int t;
int n;
void solve(){
      cin>>n;
      /*拒绝屎山数学写法 拥抱树形dp 从我做起*/
      vector<int> p(n+1,0);
	//!!!!!!!!!!!!!!!!!!!!!!!空间不要开太大!!!!!!!!!!!!!!!!!!!!!!!
      vector<int> q[n+1];//直接存每一层是哪些节点
      vector<int> s(n+1,0);//s存第几层
      p[1]=1;
      s[1]=1;
      q[1].push_back(1);
      int maxlev=1;
      for(int i=2;i<=n;i++){
            cin>>p[i];
            s[i]=s[p[i]]+1;
            q[s[i]].push_back(i);
            maxlev=max_(maxlev,s[i]);
      }
      ll ans=0;
      vector<ll> dp(n+1,0);
      //每个节点对答案的贡献是扣掉自己父亲节点的个数
      dp[1]=1;
      ll res=0;
      for(auto son:q[2]){
            dp[son]=1;
            res=(res+1)%mod;
      }
      //cout<<res<<endl;
      for(int i=3;i<=maxlev;i++){
            for(auto son:q[i]){
                  dp[son]=(res-dp[p[son]]+mod)%mod;
            }
            res=0;
            for(auto son:q[i]){
                  res=(res+dp[son])%mod;
            }
            //cout<<endl;
      }
      for(int i=1;i<=n;i++){
            //cout<<dp[i]<<" ";
            ans=(ans+dp[i])%mod;
      }
      //cout<<endl;
      cout<<ans<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

Trapmigiano Reggiano

https://codeforces.com/contest/2071/problem/C
手玩一下可得

思路

根据相对位置拉来拉去->考虑固定一个 讨论另一个的性质
所有结点都要被遍历一遍->考虑先后顺序
考虑将en作为根节点 随便放几个st的位置手玩
->抓住关键结论节点不会拉到比最后一层还下面的位置
->结论:讨论层数 按层数从下到上依次输出节点就是结果
image
image

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int t;
int n,st,en;
void solve(){
      cin>>n>>st>>en;
      vector<int> tr[n+1];
      for(int i=1;i<=n-1;i++){
            int u,v;
            cin>>u>>v;
            tr[u].push_back(v);
            tr[v].push_back(u);
      }
      /*
      将树分成三块:
      (1)st阵营
      (2)en阵营
      (3)st和en之间的
      */
      //先找到st到en的路径
      queue<PII> q;
      vector<int> tree[n+1];
      q.push({en,1});
      tree[1].push_back(en);
      vector<bool> st(n+1,0);
      st[en]=1;
      int maxlev=0;
      while(!q.empty()){
            auto t=q.front();
            int no=t.first;
            int cen=t.second;
            maxlev=max(maxlev,cen);
            q.pop();
            for(auto son:tr[no]){
                  if(!st[son]){
                        int cen_=cen+1;
                        st[son]=1;
                        tree[cen_].push_back(son);
                        q.push({son,cen_});
                  }
            }
      }
      for(int i=maxlev;i>=1;i--){
            for(auto son:tree[i]){
                  cout<<son<<" ";
            }
      }
      cout<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

树上问题

https://codeforces.com/gym/105158/submit
【有向图】
【强联通分量(能连双边的)】用并查集缩点
统计出入度 入度为0的块有且只有1个且这个块的大小就是答案

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int n;
struct DSU{
    vector<int> p,sz;
	//建立并查集
    DSU(int n):p(n + 1),sz(n + 1,1){for(int i = 1;i <= n;i++)p[i] = i;}
	//找父亲+合并
    int find(int x){return (p[x] == x) ? x : p[x] = find(p[x]);}
	//查找是否相同
    bool same(int x,int y){return find(x) == find(y);}
	//合并两集合
    bool merge(int x,int y){
        x = find(x),y = find(y);
        if(x == y)return false;
        sz[x] += sz[y];
        p[y] = x;
        return true;
    }
	//查询集合内数量
    int size(int x){return sz[find(x)];}
};
void solve(){
    cin>>n;
    vector<int> a(n+1,0);
    for(int i=1;i<=n;i++) cin>>a[i];
    //并查集缩点
    DSU dsu(n);
    //邻接表存图
    vector<int> g[n+1];
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        if(a[u]*2>=a[v] && a[v]*2>=a[u]){
            //缩点合并
            dsu.merge(u,v);
        }
        //做单向边
        else if(a[u]*2>=a[v]){
            g[v].push_back(u);
        }
        else if(a[v]*2>=a[u]){
            g[u].push_back(v);
        }
    }
    //统计出入度:注意缩点->先找父亲
    set<PII> st;
    for(int i=1;i<=n;i++){
        for(auto son:g[i]){
            int fu=dsu.find(i),fv=dsu.find(son);
            if(fu==fv) continue;
            st.insert({fu,fv});
        }
    }
    vector<int> chu(n+1,0),ru(n+1,0);
    for(auto son:st){
        chu[son.first]++;
        ru[son.second]++;
    }
    //有且只有一个入度为0的强联通块 为答案
    //否则答案为0
    int flag=0;
    int ans=0;
    for(int i=1;i<=n;i++){
        int fa=dsu.find(i);
        if(i!=fa) continue;//只有fa==i的才是连通块的父亲
        if(ru[fa]==0){
            flag++;
            ans=dsu.size(fa);
        }
    }
    if(flag!=1) cout<<"0"<<endl;
    else cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

Kirei Attacks the Estate

https://codeforces.com/contest/2114/problem/E
分析。考虑多种情况。->结论
image

int n;
void solve(){
    cin>>n;
    vector<ll> a(n+1,0);
    for(int i=1;i<=n;i++) cin>>a[i];
    vector<int> g[n+1];
    vector<ll> dpmax(n+1,0),dpmin(n+1,0);
    vector<ll> ans(n+1,0);
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dpmax[1]=a[1],dpmin[1]=a[1];
    ans[1]=a[1];
    std::function<void(int, int)> dfs;
    dfs=[&](int u,int fa) -> void{
        for(auto son:g[u]){
            if(son!=fa){
                dpmax[son]=max_(a[son],a[son]-dpmin[u]);
                dpmin[son]=min_(a[son],a[son]-dpmax[u]);
                ans[son]=dpmax[son];
                dfs(son,u);
            }
        }
    };
    dfs(1,-1);
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<" ";
    }
    cout<<endl;
}
posted @ 2025-03-01 20:43  White_ink  阅读(12)  评论(0)    收藏  举报