【CodeForces】914 E. Palindromes in a Tree 点分治

【题目】E. Palindromes in a Tree

【题意】给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数。n<=2*10^5。

【算法】点分治

【题解】状压20位的二进制表示一条路径的字符状态,点分治过程中维护扫描过的路径只须维护状态桶数组,t[i]表示前面状态为i的路径条数。

合并:考虑当前状态为j,要使合并的状态满足条件即i^j=1<<k(0<=k<20)或i^j=0,移项得i=j^(1<<k)或i=j,所以路径数是Σ t [ j^(1<<k) ]+t[j]。

统计每个点:对于当前要处理的重心x,先遍历所有子树得到整个t[]数组,然后对每个子树先删除其在桶里的状态,然后扫一遍贡献子树中每个点,最后将子树的状态加回桶中。

这样可以做到每条路径都贡献到每个点,要特殊处理重心的贡献。

复杂度O(n log n)。

#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=200010,maxN=2000010;
int tot,first[maxn],sz[maxn],vis[maxn],sum,root,a[maxn],u,v,n;
ll ans[maxn],t[maxN];
struct edge{int v,from;}e[maxn*2];

void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void getroot(int x,int fa){
    sz[x]=1;
    bool ok=1;
    for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v]){
        getroot(e[i].v,x);
        sz[x]+=sz[e[i].v];
        if(sz[e[i].v]>sum/2)ok=0;
    }
    if(ok&&sz[x]>=sum/2)root=x;
}
void dfs(int x,int fa,int p,int s){
    t[s^=(1<<a[x])]+=p;
    for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])dfs(e[i].v,x,p,s);
}
ll calc(int x,int fa,int s){
    s^=(1<<a[x]);ll num=t[s];
    for(int i=0;i<20;i++)num+=t[s^(1<<i)];
    for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa&&!vis[e[i].v])num+=calc(e[i].v,x,s);
    ans[x]+=num;
    return num;
}
void solve(int x,int s){
    vis[x]=1;
    dfs(x,0,1,0);
    ll num=t[0];
    for(int i=0;i<20;i++)num+=t[1<<i];
    for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){
        dfs(e[i].v,x,-1,1<<a[x]);
        num+=calc(e[i].v,x,0);
        dfs(e[i].v,x,1,1<<a[x]);
    }
    ans[x]+=num/2;
    dfs(x,0,-1,0);
    for(int i=first[x];i;i=e[i].from)if(!vis[e[i].v]){
        if(sz[e[i].v]>sz[x])sum=s-sz[x];else sum=sz[e[i].v];
        getroot(e[i].v,x);
        solve(root,sum);
    }
}
char s[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        insert(u,v);insert(v,u);
    }
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)a[i]=s[i]-‘a‘;
    sum=n;
    getroot(1,0);
    solve(root,sum);
    for(int i=1;i<=n;i++)printf("%lld ",ans[i]+1);
    return 0;
}

原文地址:https://www.cnblogs.com/onioncyc/p/8334111.html

时间: 2024-10-07 21:58:22

【CodeForces】914 E. Palindromes in a Tree 点分治的相关文章

[2016-04-04][codeforces][639][B][Bear and Forgotten Tree 3]

时间:2016-04-04 13:11:25 星期一 题目编号:[2016-04-04][codeforces][639][B][Bear and Forgotten Tree 3] 题目大意:一棵树有n个节点,直径为d,直径为h,问,这样的树是否存在,是则输出任意一棵树的所有边 分析: 树的高度是h,那么树的直径最大为2h 所以d?2×hd?2×h 所以只需要生成第一个枝条深度为h,其他枝条深度为d-h的树即可 如果d>2×hd>2×h,那么这样的树就不存在 d == h,剩下的节点不能放在

[LeetCode] Convert Sorted List to Binary Search Tree(分治)

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 方法:为了使BST高度平衡,要找链表中的中值作为当前根节点. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) :

Codeforces Round #256 (Div. 2/C)/Codeforces448C_Painting Fence(分治)

解题报告 给篱笆上色,要求步骤最少,篱笆怎么上色应该懂吧,,,刷子可以在横着和竖着刷,不能跳着刷,,, 如果是竖着刷,应当是篱笆的条数,横着刷的话,就是刷完最短木板的长度,再接着考虑没有刷的木板,,, 递归调用,,, #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define inf 999999999999999 using namespace

Codeforces 600E. Lomsat gelral(Dsu on tree学习)

题目链接:http://codeforces.com/problemset/problem/600/E n个点的有根树,以1为根,每个点有一种颜色.我们称一种颜色占领了一个子树当且仅当没有其他颜色在这个子树中出现得比它多.求占领每个子树的所有颜色之和. 我们都知道可以$BST$启发式合并从而完美${O(nlogn^{2})}$,这太丑陋了. 那么$Dsu~~on~~tree$是在干啥呢? 找出树中每一个节点的重儿子,统计答案的时候优先进入每一个点的所有轻儿子,之后再进入重儿子,目的是保留重儿子所

Codeforces Round #540 (Div. 3) F1. Tree Cutting (Easy Version) 【DFS】

任意门:http://codeforces.com/contest/1118/problem/F1 F1. Tree Cutting (Easy Version) time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You are given an undirected tree of nn vertices. Some vert

Codeforces Round #629 (Div. 3) E. Tree Queries(lca题)

https://codeforces.com/contest/1328/problem/E E. Tree Queries You are given a rooted tree consisting of nn vertices numbered from 11 to nn. The root of the tree is a vertex number 11. A tree is a connected undirected graph with n−1n−1 edges. You are

Codeforces Round #316 (Div. 2) D. Tree Requests 树 离线在线 算法

D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a lowercase English letter. Vertex 1 is the root of the

Codeforces Round #353 (Div. 2) D. Tree Construction (二分,stl_set)

题目链接:http://codeforces.com/problemset/problem/675/D 给你一个如题的二叉树,让你求出每个节点的父节点是多少. 用set来存储每个数,遍历到a[i]的时候查找比a[i]大的数的位置,然后插入,而父亲就是刚好比a[i]小的数或刚好大的数. 然后讨论是哪一个数. 比如给你3 1 2 ,如图 1的父亲是3 ,2的父亲是1. 那我其实只要找左边或右边出现最晚的数就行了,用pair的first表示a[i],second表示出现的顺序i. 1 #include

数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction

Tree Construction Problem's Link ---------------------------------------------------------------------------- Mean: 给定n个数,按照构造Binary Search Tree的方式来构造BST树,按顺序输出每一个非root结点的父节点的值. analyse: 构造BST树最坏情况下时间复杂度为O(n),肯定会超时. 注意到只需要输出结点的父节点的值,不需要真的构造BST树. 插到第i