yuwj  

没错,这两天迷上了这个算法,这是我进阶中高级算法学习的第一步!
(虽然之前也搞过AC自动机、Tire数,但是效果不怎样,都是一两天就结束了,题目也没搞几个,就会简单应用,但是好像也足够了...)

我已经连续4、5天没有吃晚饭了,现在头有点昏昏的,不知道是不是饿了,反正脑子是一点都转不了,有时候还有点精神恍惚。。。

今天又是调了1天的dsu on tree的代码,过了两个题,但是搞懂了一点,这里先不写思路了,真的昏昏沉沉aaaa

CF1709
代码:

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define dwn(i,a,b) for(int i = a; i >= b; i--)
#define vi vector<int>
typedef long long ll;
const int N = 2e5+10;
int n, d[N], a[N], ans;
vector<int> g[N];
set<int> s[N]; //每棵树的前缀和集合
 
//找lca啊,路径权值抑或和
void dfs(int u, int fa){
    s[u].insert(d[u]);
 
    bool flg = 0;
    for(auto v : g[u]){
        if(v == fa) continue;
        d[v] = d[u] ^ a[v];
        dfs(v,u);
 
        if(s[u].size() < s[v].size()) swap(s[u],s[v]);
        for(auto x : s[v]){
            if(s[u].find(x ^ a[u]) != s[u].end()) flg = 1;
        }
 
        for(auto x : s[v]) s[u].insert(x);
    }
 
    if(flg) ans++, s[u].clear();
}
 
void solve(){
    cin >> n;
    rep(i,1,n) cin >> a[i];
 
    rep(i, 1, n-1){
        int u, v; cin >> u >> v;
        g[u].pb(v);
        g[v].pb(u);
    }
 
    d[1] = a[1];
    dfs(1,0);
    cout << ans << '\n';
}
 
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	//int _;cin>>_;while(_--)
	solve();return 0;
}

CF600E
醉了,一个板子调了4h
代码:

// /*
// 询问子树信息:考虑dsu on tree
// 题意:a向下b层能不能构成回文串?
//     检查以a为根的子树,第b层颜色种类奇数个数 <= 1即可
// */
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
using ll = long long;
int n;
int g[MAXN],tot,dfn,u,v;
int sz[MAXN],deep[MAXN],fa[MAXN],son[MAXN],L[MAXN],R[MAXN],Index[MAXN],skp,col[MAXN],nowans,cnt[MAXN];

//图的存储
//int tot, g[MAXN];
struct edges
{
    int to, nxt;
}e[2 * MAXN];

void add_edge(int from, int to){
    e[++tot].to = to;
    e[tot].nxt = g[from];
    g[from] = tot;
}

//树剖 + 维护dfn序
//int sz[MAXN], deep[MAXN], son[MAXN], fa[MAXN], L[MAXN], R[MAXN], Index[MAXN];
void dfs(int x, int dep, int father){
    sz[x] = 1, deep[MAXN] = dep, son[x] = 0, fa[x] = father;
    L[x] = ++dfn, Index[dfn] = x;
    
    for(int i = g[x]; i; i = e[i].nxt){
        if(e[i].to == father)continue;
        dfs(e[i].to, dep+1, x);
        
        sz[x] += sz[e[i].to];
        if(!son[x] || sz[son[x]] < sz[e[i].to]) son[x] = e[i].to;
    }

    R[x] = dfn;
}

//int skp, cnt[MAXN], col[MAXN], nowans, ans[MAXN];

// dsu:数据结构维护信息:每颗子树的颜色种类数,增加,删除
ll max_cnt, max_col, sum,ans[MAXN];
void get_data(int x){
    for(int i = L[x]; i <= R[x]; i++){
        if(Index[i] == skp){
            i = R[Index[i]];
            continue;
        }

        int c = col[Index[i]];
        cnt[c]++;
        if(cnt[c] > max_cnt){
            max_cnt = cnt[c];
            sum = c;
        }else if(cnt[c] == max_cnt){
            sum += c;
        }
    }
}

void del_data(int x){
    for(int i = L[x]; i <= R[x]; i++){
        if(skp == Index[i]) {
            i = R[Index[i]];
            continue;
        }

        cnt[col[Index[i]]]--;
    }
}

void dsu(int x, bool tag){
    for(int i = g[x]; i; i = e[i].nxt){
        if(e[i].to == son[x] || e[i].to == fa[x]) continue;
        dsu(e[i].to, 1);
    }

    if(son[x]){
        dsu(son[x],0);
        skp = son[x];
    }

    get_data(x); // 处理轻儿子
    ans[x] = sum;

    if(tag){ //轻儿子删除数据结构中的信息
        skp = 0;
        sum = max_cnt = 0;
        del_data(x);
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &col[i]);
    }

    for(int i = 1; i <= n-1; i++){
        scanf("%d%d", &u, &v);
        add_edge(u,v);
        add_edge(v,u);
    }

    dfs(1,0,-1);
    dsu(1,0);
    for(int i = 1; i <= n; i++){
        printf("%lld%c", ans[i], " \n"[i == n]);
    }
    return 0;
}

状态很差,希望我还能活到今晚22:35的edu场

posted on 2025-04-28 21:27  xiaowang524  阅读(26)  评论(0)    收藏  举报