http://acm.hdu.edu.cn/showproblem.php?pid=5039
给定一棵树,边权为0/1。m个操作支持翻转一条边的权值或者询问树上有多少条路径的边权和为奇数。
用树形dfs出每个点到根的路径上边权和是否为奇数;
由于翻转一个边只会连带影响其下的子节点,所有线段树记录更新区间,odd记录到根的路径上边权和为奇数的个数,每次只需更新和查询odd,没有lazy会超时
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <queue> #include <map> #include <iostream> #include <algorithm> using namespace std; #define RD(x) scanf("%d",&x) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define clr0(x) memset(x,0,sizeof(x)) typedef long long LL; #define L(x) (x<<1) #define R(x) ((x<<1)|1) #define MI(x,y) ((x+y)>>1) const int maxn = 30010; int head[maxn],l[maxn],r[maxn],val[maxn]; int n,m,tot,idx; struct edge{ int u,v,f,next; }ed[maxn<<1]; map<string , int> hash; struct tree{ int l,r,odd,// odd为到根的路径上边权和为奇数的个数 lazy;// lazy控制翻转次数,翻转偶数次相当于没有翻转 }d[maxn<<2]; void add(int u,int v,int f) { ed[tot] = (edge){u,v,f,head[u]},head[u] = tot++; ed[tot] = (edge){v,u,f,head[v]},head[v] = tot++; } void dfs(int u,int f,int fa) { idx++; val[idx] = f; l[u] = idx; for(int i = head[u];i != -1;i = ed[i].next){ if(ed[i].v != fa){ dfs(ed[i].v,f ^ ed[i].f,u); } } r[u] = idx; } void up(int root) { d[root].odd = d[L(root)].odd + d[R(root)].odd; } void build(int l,int r,int root) { d[root] = (tree){l,r,val[l],0}; if(l == r) return ; int mid = MI(l,r); build(l,mid,L(root)); build(mid+1,r,R(root)); up(root); } void down(int root) { if (d[root].lazy) { d[L(root)].lazy ^= 1;// 翻转偶数次相当于没翻转,所以不需要更新其子节点 d[R(root)].lazy ^= 1; d[L(root)].odd = d[L(root)].r - d[L(root)].l + 1 - d[L(root)].odd; d[R(root)].odd = d[R(root)].r - d[R(root)].l + 1 - d[R(root)].odd; d[root].lazy = 0; } } void update(int l, int r, int root) { if (d[root].l == l && d[root].r == r) { d[root].odd = d[root].r - d[root].l + 1 - d[root].odd; d[root].lazy ^= 1; return; } down(root); int mid = MI(d[root].l,d[root].r); if (r <= mid) update(l, r, L(root)); else if (l > mid) update(l, r, R(root)); else { update(l, mid, L(root)); update(mid + 1, r, R(root)); } up(root); } int main() { int _; RD(_); string str,rts; char q[2]; for(int cas = 1;cas <= _;++cas){ printf("Case #%d:\n", cas); hash.clear(); RD(n); for(int i = 1;i <= n;++i){ cin>>str; hash[str] = i; head[i] = -1; } tot = 0; int u,v,f; for(int i = 1;i < n;++i){ cin>>str>>rts; RD(f); add(hash[str],hash[rts],f); } idx = 0; dfs(1,0,0); build(1,n,1); RD(m); while(m--){ scanf("%s",q); if(q[0] == 'Q'){ printf("%d\n",d[1].odd * (n - d[1].odd) * 2); }else{ RD(f); f = (f-1)<<1;// 边的记录用例两单位的ed u = ed[f].u,v = ed[f].v; if(l[u] > l[v]) update(l[u],r[u],1); else update(l[v],r[v],1); } } } return 0; }