Little Devil I

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 894    Accepted Submission(s): 296

Problem Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

The devil likes to make thing in chaos. This kingdom’s road system is like simply a tree(connected graph without cycle). A road has a color of black or white. The devil often wants to make some change of this system.

In details, we call a path on the tree from a to b consists of vertices lie on the shortest simple path between a and b. And we say an edge is on the path if both its two endpoints is in the path, and an edge is adjacent to the path if exactly one endpoint of it is in the path.

Sometimes the devil will ask you to reverse every edge’s color on a path or adjacent to a path.

The king’s daughter, WJMZBMR, is also a cute loli, she is surprised by her father’s lolicon-like behavior. As she is concerned about the road-system’s status, sometimes she will ask you to tell there is how many black edge on a path.

Initially, every edges is white.

 
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains an integer n, which is the size of the tree. The vertices be indexed from 1.
On the next n-1 lines, each line contains two integers a,b, denoting there is an edge between a and b. 
The next line contains an integer Q, denoting the number of the operations.
On the next Q lines, each line contains three integers t,a,b. t=1 means we reverse every edge’s color on path a to b. t=2 means we reverse every edge’s color adjacent to path a to b. t=3 means we query about the number of black edge on path a to b.

T<=5.
n,Q<=10^5.
Please use scanf,printf instead of cin,cout,because of huge input.

 
Output
For each t=3 operation, output the answer in one line.
 
Sample Input
1
10
2 1
3 1
4 1
5 1
6 5
7 4
8 3
9 5
10 6

10
2 1 6
1 3 8
3 8 10
2 3 4
2 10 8
2 4 10
1 7 6
2 7 3
2 1 4
2 10 10

 
Sample Output
3
/*
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;
}

  

hdu 4897 树链剖分(重轻链)的更多相关文章

  1. hdu 5893 (树链剖分+合并)

    List wants to travel Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/O ...

  2. hdu 5274 树链剖分

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  3. hdu 5052 树链剖分

    Yaoge’s maximum profit Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...

  4. HDU 3966 (树链剖分+线段树)

    Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板 ...

  5. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  6. HDU 3966 /// 树链剖分+树状数组

    题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...

  7. HDU 5242 树链剖分思想的贪心

    题意及博客 树链剖分分为2步,第一次求出深度,重儿子,第二次求出重链,用到了启发式的思想,即对于比较重的儿子,尽量去完整的维护它.类似于我们去合并两个堆,明显把小的堆逐个插入大的堆中会比大的往小的插更 ...

  8. hdu 4729 树链剖分

    思路:这个树链剖分其实还是比较明显的.将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数.当A<=B时,就全部建新的管子. 对于A>B的情况比较 建一条 ...

  9. hdu 3966 树链剖分

    思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...

随机推荐

  1. JAVA接口基础知识总结

    1:是用关键字interface定义的. 2:接口中包含的成员,最常见的有全局常量.抽象方法. 注意:接口中的成员都有固定的修饰符. 成员变量:public static final     成员方法 ...

  2. 201421123042 《Java程序设计》第7周学习总结

    1. 本周学习总结 1.1 思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. 事件源 事件对象 事件监听器 事件适合配器 1.2 ...

  3. 关于java中的数组

    前言:最近刚刚看完了<Java编程思想>中关于数组的一章,所有关于Java数组的知识,应该算是了解的差不多了.在此再梳理一遍,以便以后遇到模糊的知识,方便查阅. Java中持有对象的方式, ...

  4. nyoj 开方数

    开方数 时间限制:500 ms  |  内存限制:65535 KB 难度:3   描述 现在给你两个数 n 和 p ,让你求出 p 的开 n 次方.   输入 每组数据包含两个数n和p.当n和p都为0 ...

  5. C# 大数组赋值给小数组,小数组赋值给大数组

    ]; ]; " }; arraymax = arraystr;//变成和arraystr一样 arraymin = arraystr;//变成和arraystr一样

  6. php实现单,双向链表,环形链表解决约瑟夫问题

    传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季  http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求 ...

  7. js的构造函数共用事例

    在使用构造函数去实现一种功能时,我们有时候往往需要实现这个功能,会因此产生多个堆内对象.这样就会造成堆内存滥用.占用不该占用的空间.为此我们可以利用函数把共用的内容封装起来.放便我们的使用.很多东西其 ...

  8. 基于 Java NIO 实现简单的 HTTP 服务器

    1.简介 本文是上一篇文章实践篇,在上一篇文章中,我分析了选择器 Selector 的原理.本篇文章,我们来说说 Selector 的应用,如标题所示,这里我基于 Java NIO 实现了一个简单的 ...

  9. 新概念英语(1-15)Your passports please

    Is there a problem wtih the Customers officer? A:Are you Swedish? B:No. We are not. We are Danish. A ...

  10. SpringCloud的服务消费者 (一):(rest+ribbon)访问注册的微服务

    采用Ribbon或Feign方式访问注册到EurekaServer中的微服务.1.Ribbon实现了客户端负载均衡,Feign底层调用Ribbon2.注册在EurekaServer中的微服务api,不 ...