HDU5039--Hilarity DFS序+线段树区间更新 14年北京网络赛

题意:n个点的树,每个条边权值为0或者1, q次操作

Q 路径边权抑或和为1的点对数, (u, v)(v, u)算2个。

M i修改第i条边的权值 如果是0则变成1, 否则变成0

作法: 我们可以求出每个点到根节点路径边权抑或和为val, 那么ans = val等于0的个数乘val等于1的个数再乘2。

注意到每一次修改操作,只会影响以u为根的子树(假设边为u----v  dep[v] > dep[u]), 那么每次只需把子树区间的值与1抑或就行了。 这一步可以用线段树区间更新。

比赛时过的人好少。。。好奇怪。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN = 3e4 + 1;
  4 struct Edge {
  5     int to, cost;
  6     Edge (int to, int cost){
  7         this->to = to, this->cost = cost;
  8     }
  9 };
 10 vector <Edge> G[MAXN];
 11 int val[MAXN];
 12 int siz[MAXN], pt1[MAXN], pt2[MAXN], IDX, dep[MAXN];
 13 void dfs(int u, int father, int k) {
 14     val[u] = k;
 15     dep[u] = dep[father] + 1;
 16     pt1[u] = ++IDX;
 17     for (Edge e: G[u]) {
 18         int v = e.to;
 19         if (v != father) {
 20             dfs(v, u, k^e.cost);
 21         }
 22     }
 23     pt2[u] = IDX;
 24 }
 25 int seg[2][MAXN << 2], lazy[MAXN << 2];
 26 void push_down (int pos) {
 27     if (lazy[pos]) {
 28         swap(seg[0][pos<<1], seg[1][pos<<1]);
 29         swap(seg[0][pos<<1|1], seg[1][pos<<1|1]);
 30         lazy[pos<<1] ^= lazy[pos];
 31         lazy[pos<<1|1] ^= lazy[pos];
 32         lazy[pos] = 0;
 33     }
 34 }
 35 void build (int l, int r, int pos, int x, int d) {
 36     if (l == r) {
 37         seg[0][pos] = d == 0;
 38         seg[1][pos] = d == 1;
 39         return;
 40     }
 41     int mid = (l + r) >> 1;
 42     if (x <= mid) {
 43         build(l, mid, pos<<1, x, d);
 44     } else {
 45         build(mid+1, r, pos<<1|1, x, d);
 46     }
 47     seg[0][pos] = seg[0][pos<<1] + seg[0][pos<<1|1];
 48     seg[1][pos] = seg[1][pos<<1] + seg[1][pos<<1|1];
 49 }
 50 void update (int l, int r, int pos, int ua, int ub) {
 51     if (ua <= l && ub >= r) {
 52         lazy[pos] ^= 1;
 53         swap(seg[0][pos], seg[1][pos]);
 54         return;
 55     }
 56     push_down(pos);
 57     int mid = (l + r) >> 1;
 58     if (ua <= mid) {
 59         update(l, mid, pos<<1, ua, ub);
 60     }
 61     if (ub > mid) {
 62         update(mid+1, r, pos<<1|1, ua, ub);
 63     }
 64     seg[0][pos] = seg[0][pos<<1] + seg[0][pos<<1|1];
 65     seg[1][pos] = seg[1][pos<<1] + seg[1][pos<<1|1];
 66 }
 67 void init () {
 68     IDX = 0;
 69     memset(lazy, 0, sizeof (lazy));
 70     memset(seg, 0, sizeof seg);
 71     for (int i = 0; i < MAXN; i++) {
 72         G[i].clear();
 73     }
 74 }
 75 pair <int, int> edge[MAXN];
 76 int main() {
 77 #ifndef ONLINE_JUDGE
 78     freopen("in.txt", "r", stdin);
 79 #endif // ONLINE_JUDGE
 80     int T, cas = 1;
 81     scanf ("%d", &T);
 82     while (T--) {
 83         init();
 84         int n, q;
 85         int tot = 0;
 86         map <string, int> mp;
 87         scanf ("%d", &n);
 88         for (int i = 1; i <= n; i++) {
 89             char buff[15];
 90             scanf ("%s", buff);
 91             mp[buff] = ++tot;
 92         }
 93         for (int i = 0; i < n-1; i++) {
 94             char name1[15], name2[15];
 95             int status;
 96             scanf ("%s%s%d", name1, name2, &status);
 97             edge[i] = make_pair(mp[name1], mp[name2]);
 98             G[edge[i].first].push_back(Edge(edge[i].second, status));
 99             G[edge[i].second].push_back(Edge(edge[i].first, status));
100         }
101         dfs(1, 0, 0);
102         build(1, IDX, 1, pt1[1], 0);
103         for (int i = 0; i < n-1; i++) {
104             int u = edge[i].first;
105             int v = edge[i].second;
106             if (dep[u] > dep[v]) {
107                 swap(u, v);
108             }
109             build(1, IDX, 1, pt1[v], val[v]);
110         }
111         scanf ("%d", &q);
112         printf("Case #%d:\n", cas++);
113         for (int i = 0; i < q; i++) {
114             char kind[5];
115             scanf ("%s", kind);
116             if (kind[0] == ‘Q‘) {
117                 printf("%d\n", seg[0][1] * seg[1][1] * 2);
118             } else {
119                 int e;
120                 scanf ("%d", &e);
121                 int u = edge[e-1].first;
122                 int v = edge[e-1].second;
123                 if (dep[u] > dep[v]) {
124                     swap(u, v);
125                 }
126                 update(1, IDX, 1, pt1[v], pt2[v]);
127             }
128         }
129     }
130     return 0;
131 }
时间: 2024-12-14 16:57:13

HDU5039--Hilarity DFS序+线段树区间更新 14年北京网络赛的相关文章

HDU Hilarity (dfs序+线段树)

Problem Description After June 1st, elementary students of Ted Land are still celebrating "The Sacred Day of Elementary Students". They go to the streets and do some elementary students stuff. So we call them "elementary students". The

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

codevs1228 (dfs序+线段树)

总结: 第一次遇到dfs序的问题,对于一颗树,记录节点 i 开始搜索的序号 Left[i] 和结束搜索的序号 Righti[i],那么序号在 Left[i] ~ Right[i] 之间的都是节点 i 子树上的节点. 并且此序号与线段树中 L~R 区间对应,在纸上模拟了几遍确实如此,但暂时还未理解为何对应. 此题就是dfs序+线段树的裸题 代码: #include<iostream> #include<vector> #include<cstring> #include&

Educational Codeforces Round 6 E dfs序+线段树

题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili上电子科技大学发的视频学习的 将一颗树通过dfs编号的方式 使每个点的子树的编号连在一起作为相连的区间 就可以配合线段树搞子树 因为以前好像听说过 线段树可以解决一种区间修改和查询区间中不同的xx个数...所以一下子就想到了... 但是我不会写线段树..只会最简单的单点修改区间查询...不会用延迟标

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

hihocoder 1080 线段树(区间更新)

题目链接:http://hihocoder.com/problemset/problem/1080 , 两种操作的线段树(区间更新). 这道题前一段时间一直卡着我,当时也是基础不扎实做不出来,今天又想了想其实还是比较简单的,也只能怪自己太弱了. 这道题坑就坑在是有两个操作:set和add,所以lazy标记数组就需要两个,但是有一点要考虑的是一个区间上set与add的先后关系——如果对于一个区间set和add标记同时存在,那么应该如果处理:一种情况set在add之前,那么就按照正常顺序来就可以了: