标签:
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 894 Accepted Submission(s): 296
/* hdu 4897 树链剖分(重轻链) problem: 给你一棵树,初始每条边为白色,然后是三种操作 1.将u->v链上面的所有边的颜色翻转 (例:white -> black) 这个在线段树上很好处理,用个翻转标记,然后记录数量即可 2.将u->v链上面所有邻接的边翻转(边上只有一个点在链上面) 3.询问u->v上面有多少黑色的边 solve: 对于1,3操作树链剖分很好解决。但是在操作2上面就GG了.所以去参考了很多博客 - -,很久才明白大致思路 就操作2而言,主要可以看成在一条重链上面的 和 跨越了很多重轻链的那种. 主要是轻链两端连接的是重链,所以在操作2的时候可以考虑直接在每个点上面打标记(除了有的叶子节点,重链基本上 覆盖了所有的点). 所以轻链的颜色就是: 左端点rev2^右端点rev2^边的颜色(边的颜色线段树很好维护的) 如果重链分成很多条边来用也可以实现,但是无疑到达lca的效率为很低,所有需要考虑其他方法 然后就是维护重链上面的颜色,如果u,v在一条重链的中间部分,打标记可以维护对轻链的影响。所以只需要考虑对两端重链 的影响,于是把与两端相邻的边用操作1翻转就好了.在操作2下一条重链最多只需要更新左右两个端点,但是却有很多条 轻链。 所以重链可以直接更新,轻链则需要标记来维护了。 因为没有判断,有时线段树会出现l>r导致RE了很久- - hhh-2016-08-18 21:18:55 */ #pragma comment(linker,"/STACK:124000000,124000000") #include <algorithm> #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <vector> #include <map> #define lson i<<1 #define rson i<<1|1 #define ll long long #define clr(a,b) memset(a,b,sizeof(a)) #define key_val ch[ch[root][1]][0] using namespace std; const int maxn = 200100; const int inf = 0x3f3f3f3f; int head[maxn],tot,pos,son[maxn]; int top[maxn],fp[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn]; int n; struct Edge { int to,next; } edge[maxn<<2]; void ini() { tot = 0,pos = 1; clr(head,-1),clr(son,-1); } void add_edge(int u,int v) { edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++; } void dfs1(int u,int pre,int d) { // cout << u << " " <<pre <<" " <<d <<endl; dep[u] = d; fa[u] = pre,num[u] = 1; for(int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if(v != pre) { dfs1(v,u,d+1); num[u] += num[v]; if(son[u] == -1 || num[v] > num[son[u]]) son[u] = v; } } } void getpos(int u,int sp) { top[u] = sp; p[u] = pos++; fp[p[u]] = u; if(son[u] == -1)return ; getpos(son[u],sp); for(int i = head[u]; ~i ; i = edge[i].next) { int v = edge[i].to; if(v != son[u] && v != fa[u]) getpos(v,v); } } struct node { int l,r,mid; int rev1,rev2; int num; } tree[maxn << 2]; void push_up(int i) { tree[i].num = tree[lson].num + tree[rson].num; } void build(int i,int l,int r) { tree[i].l = l,tree[i].r = r; tree[i].mid=(l+r) >>1; tree[i].rev1 = tree[i].rev2 = 0; tree[i].num = 0; if(l == r) { // cout << fp[l] <<" " <<val[fp[l]]<<endl; return; } build(lson,l,tree[i].mid); build(rson,tree[i].mid+1,r); } void push_down(int i) { if(tree[i].rev1) { tree[i].rev1 = 0; tree[lson].rev1 ^= 1,tree[lson].num = tree[lson].r-tree[lson].l+1-tree[lson].num; tree[rson].rev1 ^= 1,tree[rson].num = tree[rson].r-tree[rson].l+1-tree[rson].num;; } if(tree[i].rev2) { tree[i].rev2 = 0; tree[lson].rev2 ^= 1; tree[rson].rev2 ^= 1; } } void update_area(int i,int l,int r,int flag) { // cout <<"l:"<< l <<" r:"<<r <<" min:"<< tree[i].Min<<endl; if(l > r) return ; if(tree[i].l >= l && tree[i].r <= r) { if(flag == 1) { tree[i].num = tree[i].r-tree[i].l+1-tree[i].num; tree[i].rev1 ^= 1; } else tree[i].rev2 ^= 1; return ; } push_down(i); int mid = tree[i].mid; if(r <= mid) update_area(lson,l,r,flag); else if(l > mid) update_area(rson,l,r,flag); else { update_area(lson,l,mid,flag); update_area(rson,mid+1,r,flag); } push_up(i); } int query(int i,int l,int r,int flag) { if(l > r) return 0; if(tree[i].l >= l && tree[i].r <= r) { if(flag == 1) return tree[i].num; else return tree[i].rev2; } push_down(i); int mid = tree[i].mid; if(r <= mid) return query(lson,l,r,flag); else if(l > mid) return query(rson,l,r,flag); else return query(lson,l,mid,flag)+query(rson,mid+1,r,flag); push_up(i); } void update_rev1(int u,int v) { int f1 = top[u],f2 = top[v]; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2),swap(u,v); } update_area(1,p[f1],p[u],1); u = fa[f1],f1 = top[u]; } if(dep[u] > dep[v]) swap(u,v); update_area(1,p[son[u]],p[v],1); } void update_rev2(int u,int v) { int f1 = top[u],f2 = top[v]; // cout << u << " " <<v<<endl; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2),swap(u,v); } update_area(1,p[f1],p[u],2); int par = fa[f1]; if(son[par] == f1) update_area(1,p[f1],p[f1],1); if(son[u] != -1) update_area(1,p[son[u]],p[son[u]],1); u = fa[f1],f1 = top[u]; } if(dep[u] > dep[v]) swap(u,v); update_area(1,p[u],p[v],2); int par = fa[u]; // cout <<par <<" "<< son[v] <<endl; if(son[par] == u && par > 0) update_area(1,p[u],p[u],1); if(son[v] != -1) update_area(1,p[son[v]],p[son[v]],1); } int Find(int u,int v) { // cout <<"*********************************************************"<<endl; int f1 = top[u],f2 = top[v]; int ans = 0; // cout << u << " " <<v<<endl; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2),swap(u,v); } ans += query(1,p[f1]+1,p[u],1); // cout <<ans <<" " <<f1 <<" " <<u <<endl; ans += query(1,p[fa[top[u]]],p[fa[top[u]]],2)^query(1,p[top[u]],p[top[u]],2) ^query(1,p[top[u]],p[top[u]],1); // cout <<ans<<" "<<fa[f1]<<" "<<u <<endl; u = fa[f1],f1 = top[u]; } if(dep[u] > dep[v]) swap(u,v); // cout << query(1,p[u]+1,p[v],1) <<endl; return ans+query(1,p[u]+1,p[v],1); } int main() { // freopen("in.txt","r",stdin); int T,cas = 1,op; int a,b; int m,u,v; scanf("%d",&T); while(T--) { ini(); scanf("%d",&n); for(int i =1; i <n; i++) { scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs1(1,0,0); getpos(1,1); build(1,1,pos-1); scanf("%d",&m); for(int i = 1; i <= m; i++) { scanf("%d%d%d",&op,&a,&b); // cout << op <<" " <<a <<" " <<b<<endl; if(op == 1) { if(a == b) continue; update_rev1(a,b); } else if(op == 2) { update_rev2(a,b); } else if(op == 3) { printf("%d\n",Find(a,b)); } } } return 0; }
标签:
原文地址:http://www.cnblogs.com/Przz/p/5792194.html