Little Devil I
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1039 Accepted Submission(s): 353
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.
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.
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
3Hintreverse color means change from white to black or vice virsa.
Author
WJMZBMR
Source
Recommend
【分析】
膜拜蒟蒻CZY,数据结构被众生碾压。
这道题的1、3询问很好搞,是树链剖分模板。
但是第二问比较奇葩...相邻边取反。
考虑到树链剖分中树的性质:一条链上的轻边个数最多至log级别。
所以我们可以把轻重链分开考虑,造两棵线段树。
考虑2操作。对于一条重链,把这条重链上的节点都打上轻边翻转标记。
这条重链的底部,也就是深度最大位置,记为x。由于打的是轻边翻转标记,所以x相连的轻边都被翻转,但我们还要翻转x重儿子与x之间的重链,所以这时候手动翻转一下x与其重儿子的链即可。
对于一条链两个端点的LCA需要特殊考虑,因为它的父亲边可能是重链或者轻链。如果是重链还要手动翻转。
查询操作对于轻边就特殊判断,因为只有log条,根据它的左右端点异或情况判断颜色。
写了两个版本,一个是分析对应的,一个是silvernebulaYY出来的。
大同小异。
【代码(分析版)】
//hdu 4897 Little Devil I
#include<bits/stdc++.h>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=400005;
int n,m,T,Q,cnt,tot;
int head[mxn],pos[mxn];
struct edge {int to,next;} f[mxn<<1];
struct node {int s,e,top,dep,son,fa,size;} e[mxn];
struct SEG
{
struct seg {int l,r,sum,rev;} t[mxn<<2];
inline void build(int num,int l,int r)
{
t[num].l=l,t[num].r=r;
if(l==r) return;
int mid=l+r>>1;
build(num<<1,l,mid),build(num<<1|1,mid+1,r);
}
inline void update(int num)
{
t[num].sum=(t[num<<1].sum+t[num<<1|1].sum);
}
inline void pushdown(int num)
{
if(t[num].rev)
{
t[num<<1].rev^=1;
t[num<<1|1].rev^=1;
t[num<<1].sum=(t[num<<1].r-t[num<<1].l+1)-t[num<<1].sum;
t[num<<1|1].sum=(t[num<<1|1].r-t[num<<1|1].l+1)-t[num<<1|1].sum;
t[num].rev=0;
}
}
inline void reverse(int num,int L,int R)
{
if(L<=t[num].l && t[num].r<=R)
{
t[num].rev^=1;
t[num].sum=(t[num].r-t[num].l+1)-t[num].sum;
return;
}
pushdown(num);
if(L<=t[num<<1].r) reverse(num<<1,L,R);
if(R>=t[num<<1|1].l) reverse(num<<1|1,L,R);
update(num);
}
inline int query(int num,int L,int R)
{
if(L>R) return 0;
if(L<=t[num].l && t[num].r<=R)
return t[num].sum;
int ans=0;
pushdown(num);
if(L<=t[num<<1].r) ans+=query(num<<1,L,R);
if(R>=t[num<<1|1].l) ans+=query(num<<1|1,L,R);
return ans;
}
}W,L;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void dfs1(int u)
{
e[u].size=1;
for(int i=head[u];i;i=f[i].next)
{
int v=f[i].to;
if(v==e[u].fa) continue;
e[v].dep=e[u].dep+1;
e[v].fa=u;
dfs1(v);
e[u].size+=e[v].size;
if(e[v].size>e[e[u].son].size)
e[u].son=v;
}
}
inline void dfs2(int u,int top)
{
e[u].top=top;
e[u].s=(++tot);
pos[tot]=u;
if(e[u].son)
{
dfs2(e[u].son,top);
for(int i=head[u];i;i=f[i].next)
{
int v=f[i].to;
if(v==e[u].fa || v==e[u].son)
continue;
dfs2(v,v);
}
}
e[u].e=tot;
}
inline void add(int u,int v)
{
f[++cnt].to=v,f[cnt].next=head[u],head[u]=cnt;
}
inline void change(int x,int y,bool flag)
{
int f1=e[x].top,f2=e[y].top;
while(f1!=f2)
{
if(e[f1].dep<e[f2].dep)
swap(f1,f2),swap(x,y);
if(flag)
{
L.reverse(1,e[f1].s,e[x].s);
W.reverse(1,e[f1].s,e[f1].s);
if(e[x].son) W.reverse(1,e[e[x].son].s,e[e[x].son].s);
}
else W.reverse(1,e[f1].s,e[x].s);
x=e[f1].fa;
f1=e[x].top;
}
if(e[x].dep>e[y].dep) swap(x,y);
if(flag)
{
L.reverse(1,e[x].s,e[y].s);
W.reverse(1,e[x].s,e[x].s);
if(e[y].son) W.reverse(1,e[e[y].son].s,e[e[y].son].s);
}
else if(x!=y) W.reverse(1,e[e[x].son].s,e[y].s);
}
inline int getsum(int x,int y)
{
int ans=0;
int f1=e[x].top,f2=e[y].top;
while(f1!=f2)
{
if(e[f1].dep<e[f2].dep)
swap(f1,f2),swap(x,y);
if(x!=f1) ans+=W.query(1,e[e[f1].son].s,e[x].s);
ans+=W.query(1,e[f1].s,e[f1].s)^L.query(1,e[e[f1].fa].s,e[e[f1].fa].s);
x=e[f1].fa,f1=e[x].top;
}
if(e[x].dep>e[y].dep) swap(x,y);
if(x!=y) ans+=W.query(1,e[e[x].son].s,e[y].s);
return ans;
}
inline void clear()
{
cnt=tot=0;
M(head),M(W.t),M(L.t),M(e); //e.son
}
int main()
{
int i,j,u,v,x,y,opt;
T=read();
while(T--)
{
clear();
n=read();
fo(i,2,n)
{
u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,1);
W.build(1,1,n);
L.build(1,1,n);
Q=read();
while(Q--)
{
opt=read(),x=read(),y=read();
if(opt==1) change(x,y,0);
else if(opt==2) change(x,y,1);
else printf("%d\n",getsum(x,y));
}
}
return 0;
}
/*
1
3
1 2
2 3
100
*/
【Silvernebula】
//hdu 4897 Little Devil I
#include<bits/stdc++.h>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=400005;
int n,m,T,Q,cnt,tot;
int head[mxn],pos[mxn];
struct edge {int to,next;} f[mxn<<1];
struct node {int s,e,top,dep,son,fa,size;} e[mxn];
struct SEG
{
struct seg {int l,r,sum,rev;} t[mxn<<2];
inline void build(int num,int l,int r)
{
t[num].l=l,t[num].r=r;
if(l==r) return;
int mid=l+r>>1;
build(num<<1,l,mid),build(num<<1|1,mid+1,r);
}
inline void update(int num)
{
t[num].sum=(t[num<<1].sum+t[num<<1|1].sum);
}
inline void pushdown(int num)
{
if(t[num].rev)
{
t[num<<1].rev^=1;
t[num<<1|1].rev^=1;
t[num<<1].sum=(t[num<<1].r-t[num<<1].l+1)-t[num<<1].sum;
t[num<<1|1].sum=(t[num<<1|1].r-t[num<<1|1].l+1)-t[num<<1|1].sum;
t[num].rev=0;
}
}
inline void reverse(int num,int L,int R)
{
if(L<=t[num].l && t[num].r<=R)
{
t[num].rev^=1;
t[num].sum=(t[num].r-t[num].l+1)-t[num].sum;
return;
}
pushdown(num);
if(L<=t[num<<1].r) reverse(num<<1,L,R);
if(R>=t[num<<1|1].l) reverse(num<<1|1,L,R);
update(num);
}
inline int query(int num,int L,int R)
{
if(L>R) return 0;
if(L<=t[num].l && t[num].r<=R)
return t[num].sum;
int ans=0;
pushdown(num);
if(L<=t[num<<1].r) ans+=query(num<<1,L,R);
if(R>=t[num<<1|1].l) ans+=query(num<<1|1,L,R);
return ans;
}
}W,L;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void dfs1(int u)
{
e[u].size=1;
for(int i=head[u];i;i=f[i].next)
{
int v=f[i].to;
if(v==e[u].fa) continue;
e[v].dep=e[u].dep+1;
e[v].fa=u;
dfs1(v);
e[u].size+=e[v].size;
if(e[v].size>e[e[u].son].size)
e[u].son=v;
}
}
inline void dfs2(int u,int top)
{
e[u].top=top;
e[u].s=(++tot);
pos[tot]=u;
if(e[u].son)
{
dfs2(e[u].son,top);
for(int i=head[u];i;i=f[i].next)
{
int v=f[i].to;
if(v==e[u].fa || v==e[u].son)
continue;
dfs2(v,v);
}
}
e[u].e=tot;
}
inline void add(int u,int v)
{
f[++cnt].to=v,f[cnt].next=head[u],head[u]=cnt;
}
inline void change(int x,int y,bool flag)
{
int f1=e[x].top,f2=e[y].top;
while(f1!=f2)
{
if(e[f1].dep<e[f2].dep)
swap(f1,f2),swap(x,y);
if(flag)
{
L.reverse(1,e[f1].s,e[x].s);
W.reverse(1,e[f1].s,e[f1].s);
if(e[x].son) W.reverse(1,e[e[x].son].s,e[e[x].son].s);
}
else W.reverse(1,e[f1].s,e[x].s);
x=e[f1].fa;
f1=e[x].top;
}
if(e[x].dep>e[y].dep) swap(x,y);
if(flag)
{
L.reverse(1,e[x].s,e[y].s);
W.reverse(1,e[x].s,e[x].s);
if(e[y].son) W.reverse(1,e[e[y].son].s,e[e[y].son].s);
}
else if(x!=y) W.reverse(1,e[e[x].son].s,e[y].s);
}
inline int getsum(int x,int y)
{
int ans=0;
int f1=e[x].top,f2=e[y].top;
while(f1!=f2)
{
if(e[f1].dep<e[f2].dep)
swap(f1,f2),swap(x,y);
if(x!=f1) ans+=W.query(1,e[e[f1].son].s,e[x].s);
ans+=W.query(1,e[f1].s,e[f1].s)^L.query(1,e[e[f1].fa].s,e[e[f1].fa].s);
x=e[f1].fa,f1=e[x].top;
}
if(e[x].dep>e[y].dep) swap(x,y);
if(x!=y) ans+=W.query(1,e[e[x].son].s,e[y].s);
return ans;
}
inline void clear()
{
cnt=tot=0;
M(head),M(W.t),M(L.t),M(e); //e.son
}
int main()
{
int i,j,u,v,x,y,opt;
T=read();
while(T--)
{
clear();
n=read();
fo(i,2,n)
{
u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,1);
W.build(1,1,n);
L.build(1,1,n);
Q=read();
while(Q--)
{
opt=read(),x=read(),y=read();
if(opt==1) change(x,y,0);
else if(opt==2) change(x,y,1);
else printf("%d\n",getsum(x,y));
}
}
return 0;
}
/*
1
3
1 2
2 3
100
*/