hdu 4897 Little Devil I

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.
 

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
Hint
reverse color means change from white to black or vice virsa.
 

Author
WJMZBMR
 

Source
 

Recommend
We have carefully selected several similar problems for you:   6032  6031  6030  6029  6028 






【分析】
膜拜蒟蒻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
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值