HDU 5039 Hilarity(dfs序+线段树)
来源:互联网 发布:怎样网络上发布小说 编辑:程序博客网 时间:2024/06/06 14:19
题意:
给出一颗树,树的每条边上有权值(0或1)。
有两种操作:
1. 修改某个边的权值,0变为1,1变为0。
2. 查询当前的树有多少个不同的路径,使得路径上的权值异或和为1。
注意:起点和终点不同,算作不同一条路径。
思路:
其实发现这题是路径上的异或,那么就有更简单的做法了,因为不用真的求出所有的路径,确定一个根,那么两个点路径的权值异或和可以用它们到跟的路径的权值异或和表示。
例如:u -> v,可以分解为,节点1 -> u,节点1 -> v。
根据异或的性质,
u−>v的异或和 <==> 节点1−>u的异或和oxr节点1−>v的异或和 。这样,只需要维护每个边到跟的路径的权值的异或和就行了。dfs一下,把树形结构转为线性结构,用线段树维护,然后就可以做了。
那么最后和异或和为1的路径,就是
ans=(从跟节点开始异或和为0的路径的条数)∗(从跟节点开始异或和为0的路径的条数)∗2
因为起点和终点不同所以要*2
#pragma comment(linker, "/STACK:102400000,102400000")#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <string>#include <map>#define ls (o<<1)#define rs (o<<1|1)using namespace std;const int MAXN = 30005;//邻接表//----------------------------struct Edge { int u, v, val, order; Edge() {} Edge(int _u, int _v, int _val, int _order) { u = _u, v = _v, val = _val; order = _order; }};int index;map<string, int> mp;vector<Edge> edge[MAXN];void setIndex(string str) { if(!mp.count(str)) mp[str] = ++index;}int getIndex(string str) { return mp[str];}void init(int n) { mp.clear(); index = 0; for(int i = 0; i <= n; i++) { edge[i].clear(); }}void addEdge(int u, int v, int val, int order) { edge[u].push_back(Edge(u, v, val, order));}int lt[MAXN], rt[MAXN], color[MAXN];void dfs(int u, int pre, int sum) { int v, val, order; for(int i = 0; i < edge[u].size(); i++) { v = edge[u][i].v; val = edge[u][i].val; order = edge[u][i].order; if(v == pre) continue; lt[order] = ++index; color[index] = sum^val; dfs(v, u, sum^val); rt[order] = index; }}//----------------------------//----------------------------int sumv[MAXN<<2], cover[MAXN<<2];void pushUp(int o) { sumv[o] = sumv[ls] + sumv[rs];}void pushDown(int o, int L, int R) { if(cover[o]) { int M = (L+R)/2; cover[ls] ^= 1; sumv[ls] = (M-L+1) - sumv[ls]; cover[rs] ^= 1; sumv[rs] = (R-M) - sumv[rs]; cover[o] = 0; }}void build(int o, int L, int R) { cover[o] = 0; if(L == R) { sumv[o] = color[L]; return ; } int M = (L+R)/2; build(ls, L, M); build(rs, M+1, R); pushUp(o);}int ql, qr;void modify(int o, int L, int R) { if(ql <= L && R <= qr) { cover[o] ^= 1; sumv[o] = (R-L+1) - sumv[o]; return ; } pushDown(o, L, R); int M = (L+R)/2; if(ql <= M) modify(ls, L, M); if(qr > M) modify(rs, M+1, R); pushUp(o);}//----------------------------int n, m;char str[15], str2[15], cmd[5];void solve() { scanf("%d", &n); init(n); for(int i = 1; i <= n; i++) { scanf("%s", str); setIndex(str); } int u, v, val; for(int i = 1; i < n; i++) { scanf("%s%s%d", str, str2, &val); u = getIndex(str); v = getIndex(str2); addEdge(u, v, val, i); addEdge(v, u, val, i); } //dfs序,求区间 index = 0; dfs(1, -1, 0); build(1, 1, n); scanf("%d", &m); while(m--) { scanf("%s", cmd); if(cmd[0] == 'Q') { printf("%lld\n", 2ll*(n-sumv[1])*sumv[1]); }else { int order; scanf("%d" ,&order); ql = lt[order], qr = rt[order]; modify(1, 1, n); } }}int main() { //freopen("in.txt", "r", stdin); int T, cas = 1; scanf("%d", &T); while(T--) { printf("Case #%d:\n", cas++); solve(); } return 0;}
0 0
- hdu 5039 Hilarity(dfs序 + 线段树)
- [HDU 5039 Hilarity] DFS序+线段树
- HDU 5039 Hilarity dfs序、线段树
- HDU 5039 Hilarity(dfs序+线段树)
- HDU Hilarity (dfs序+线段树)
- 【HDU】5039 Hilarity 线段树
- dfs+线段树(hdu5039 - Hilarity)
- 【线段树】 HDOJ 5039 Hilarity
- HDU 5039 Hilarity
- hdu 5039 线段树+dfs序
- hdu 5692 (dfs序+线段树)
- hdu 4366(线段树+DFS序)
- 线段树+dfs HDU
- HDU 3974 Assign the task (线段树+dfs序)
- HDU-5692-Snacks(DFS序+线段树)
- hdu 5692 Snacks(dfs序+线段树)
- HDU 5692 Snacks (dfs序+线段树)好题!
- HDU-6039 Gear Up(线段树+DFS序)
- 欢迎使用CSDN-markdown编辑器
- 用二进制文件处理学生信息
- OpenCV的IplImage与我的CHYBitmap的互转
- 第十五周程序阅读三
- 第15周 程序阅读-二进制文件及文件的读取4
- HDU 5039 Hilarity(dfs序+线段树)
- 我——成为一个人,不再迷茫
- 每天一个linux命令(23):Linux 目录结构
- Zigbee组网原理
- 算法之二分法查找
- 第十四四周项目二 改写文件并另存
- 第十三周项目一2
- Linux下 /proc文件夹内容解析(/proc文件系统解析)
- JAVA操作properties文件