• CF914E Palindromes in a Tree


    $ color{#0066ff}{ 题目描述 }$

    给你一颗 n 个顶点的树(连通无环图)。顶点从 1 到 n 编号,并且每个顶点对应一个在‘a’到‘t’的字母。 树上的一条路径是回文是指至少有一个对应字母的排列为回文。 对于每个顶点,输出通过它的回文路径的数量。 注意:从u到v的路径与从v到u的路径视为相同,只计数一次。

    (color{#0066ff}{输入格式})

    第一行包含一个整数n(2<=n<=2*10^5)。 接下来的 n-1 行,每行包含两个整数u和v(1<=u,v<=n,u≠v)表示一条连接u和v的边。保证给出的图是一棵树。 再下一行包含一个n个字符的字符串,第i个字符对应第i个顶点。

    (color{#0066ff}{输出格式})

    输出一行,包含n个整数,第i个数表示经过顶点i的回文路径数量。

    (color{#0066ff}{输入样例})

    5
    1 2
    2 3
    3 4
    3 5
    abcbb
    
    
    7
    6 2
    4 3
    3 7
    5 2
    7 2
    1 4
    afefdfs
    

    (color{#0066ff}{输出样例})

    1 3 4 3 3 
    
    1 4 1 1 2 4 2 
    

    (color{#0066ff}{数据范围与提示})

    In the first sample case, the following paths are palindromic:

    (2−3−4)

    (2−3−5)

    (4−3−5)

    Additionally, all paths containing only one vertex are palindromic. Listed below are a few paths in the first sample that are not palindromic:

    (1−2−3)

    (1−2−3−4)

    (1−2−3−5)

    4000ms / 256MB

    (color{#0066ff}{题解})

    看到时限还有求树链的个数,肯定是点分治跑不了了

    对于当前点,把它到所有点的树链的状态搜出来存入桶中

    然后开始统计经过他的链对所有点的贡献

    对于每棵子树,先dfs一遍消去子树对桶的贡献(统计的是子树间的链)

    然后开始统计贡献

    假如当前点是u,对于任意子树中的某一点v,如果v的子树中某点k,(u-k)的链合法,那么实际上v也要+1,所以说一个点的贡献不仅仅是自己到u和其它子树到u的贡献,还有自己的孩子到u和其它子树到u的贡献,也就是说,贡献还要加上子树的贡献和!

    对于u自己的贡献还有单链的贡献,可以单独考虑

    统计完贡献, 恢复这个子树对桶的贡献,继续下一子树

    全弄完,再整个dfs一遍清空桶,分治子节点

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 2e5 + 10;
    struct node {
    	int to;
    	node *nxt;
    	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
    };
    node *head[maxn];
    std::vector<int> v, vv;
    LL ans[maxn];
    int val[maxn], sum, root;
    int t[1 << 21], f[maxn], siz[maxn];
    bool vis[maxn];
    int n;
    void add(int from, int to) {
    	head[from] = new node(to, head[from]);
    }
    int getch() {
    	char ch;
    	while(!isalpha(ch = getchar()));
    	return ch - 'a';
    }
    void getroot(int x, int fa) {
    	siz[x] = 1, f[x] = 0;
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(i->to == fa || vis[i->to]) continue;
    		getroot(i->to, x);
    		siz[x] += siz[i->to];
    		f[x] = std::max(f[x], siz[i->to]);
    	}
    	f[x] = std::max(f[x], sum - siz[x]);
    	if(f[x] < f[root]) root = x;
    }
    void dfs(int x, int fa, int zt) {
    	v.push_back(zt);
    	vv.push_back(zt);
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(i->to == fa) continue;
    		dfs(i->to, x, zt ^ (1 << val[i->to]));
    	}
    }
    void build(int x, int fa, int zt, int k) {
    	t[zt ^ (1 << val[x])] += k;
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(i->to == fa || vis[i->to]) continue;
    		build(i->to, x, zt ^ (1 << val[x]), k);
    	}
    }
    int getans(int x, int fa, int zt) {
    	int tot = t[zt ^ (1 << val[x])];
    	for(int k = 0; k <= 19; k++) tot += t[zt ^ (1 << val[x]) ^ (1 << k)];
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(i->to == fa || vis[i->to]) continue;
    		tot += getans(i->to, x, zt ^ (1 << val[x]));
    	}
    	ans[x] += tot;
    	return tot;
    }
    void calc(int x) {
    	build(x, 0, 0, 1);
    	int tot = t[0];
    	for(int i = 0; i <= 19; i++) tot += t[1 << i];
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(vis[i->to]) continue;
    		build(i->to, x, 1 << val[x], -1);
    		tot += getans(i->to, x, 0);
    		build(i->to, x, 1 << val[x], 1);
    	}
    	ans[x] += tot >> 1;
    	build(x, 0, 0, -1);
    }
    void work(int x) {
    	vis[x] = true;
    	calc(x);
    	for(node *i = head[x]; i; i = i->nxt) {
    		if(vis[i->to]) continue;
    		sum = siz[i->to], root = 0;
    		getroot(i->to, x);
    		work(root);
    	}
    }
    	
    int main() {
    	n = in();
    	int x, y;
    	for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);
    	for(int i = 1; i <= n; i++) val[i] = getch();
    	root = 0, sum = f[0] = n;
    	getroot(1, 0);
    	work(root);
    	for(int i = 1; i <= n; i++) printf("%lld%c", ans[i] + 1, i == n? '
    ' : ' ');
    	return 0;
    }
    
  • 相关阅读:
    什么是函数式编程
    红包算法
    laravel中查看执行的SQL语句
    身份证号信息后台匹配
    在函数内部访问外部的变量
    设计模式-观察者模式
    laravel查询构造器操作数据库
    linux根目录文件夹的作用
    关于laravel连接数据库报错
    设定起始日期,遍历到今天的日期
  • 原文地址:https://www.cnblogs.com/olinr/p/10484384.html
Copyright © 2020-2023  润新知