zoukankan      html  css  js  c++  java
  • 【JZOJ3360】苹果树【树上莫队】【LCA】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/3360
    给定一棵nn个节点的树,每个节点有一个颜色。查询两个节点之间路径上有多少种不同
    的颜色,一次查询可以将一种颜色视为另一种。


    思路:

    考试时就写了一条链的莫队部分分+暴力的20pts20pts。然后写炸了。暴力和莫队各有一个点没拿到qwqqwq
    正解是树上莫队。就是莫队的一个升级版本。
    先求出这棵树的欧拉序,在欧拉序上跑莫队,注意如果这个区间涵盖了一个点偶数次,那么这个点就是不在树上这两个点的路径之间的。因为这个点肯定在这个区间内进入了一次并且出去了一次。
    所以我们的莫队不能像普通的莫队一样直接写add,deladd,del,要先判断这个点的出现次数的奇偶,然后再选择add,deladd,del来修改。虽然好像没有什么区别
    细节比较多,调了好久,注意细节即可。


    代码:

    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=200010,LG=18;
    int a[N],head[N],cnt[N],ans[N],f[N][LG+1],dep[N],dfn[N],s[N],t[N],pos[N],p[N];
    int n,m,tot,T,sum,num;
    bool find[N];
    
    struct Ask
    {
    	int l,r,a,b,id;
    }ask[N];
    
    struct edge
    {
    	int to,next;
    }e[N];
    
    int read()
    {
    	int d=0;
    	char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch))
    		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    bool cmp(Ask x,Ask y)
    {
    	if (pos[x.l]<pos[y.l]) return 1;
    	if (pos[x.l]>pos[y.l]) return 0;
    	return x.r<y.r;
    }
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs1(int x,int fa)
    {
    	dfn[++num]=x;
    	s[x]=num;
    	for (int i=head[x];~i;i=e[i].next)
    		if (e[i].to!=fa) dfs1(e[i].to,x);
    	dfn[++num]=x;
    	t[x]=num;
    }
    
    void del(int x)
    {
    	cnt[a[x]]--;
    	if (!cnt[a[x]]) sum--;
    }
    
    void add(int x)
    {
    	if (!cnt[a[x]]) sum++;
    	cnt[a[x]]++;
    }
    
    void maintain(int x)
    {
    	p[x]^=1;
    	if (!p[x]) del(x);
    		else add(x);
    }
    
    void dfs2(int x,int fa)
    {
    	dep[x]=dep[fa]+1;
    	f[x][0]=fa;
    	for (int i=1;i<=LG;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa) dfs2(v,x);
    	}
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    		if (f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    
    int main()
    {
    	freopen("data.txt","r",stdin);
    	freopen("ans.out","w",stdout);
    	memset(head,-1,sizeof(head));
    	n=read(); m=read();
    	T=sqrt(n*2);
    	for (int i=1;i<=n*2;i++)
    		pos[i]=(i-1)/T+1;
    	for (int i=1;i<=n;i++)
    		a[i]=read();
    	for (int i=1,x,y;i<=n;i++)
    	{
    		x=read(); y=read();
    		add(x,y); add(y,x);
    	}
    	dfs1(0,0);
    	dfs2(0,0);
    	for (int i=1;i<=m;i++)
    	{
    		ask[i].l=read(); ask[i].r=read(); 
    		ask[i].a=read(); ask[i].b=read();
    		ask[i].id=i;
    		int LCA=lca(ask[i].l,ask[i].r);
    		if (ask[i].l==LCA)
    		{
    			swap(ask[i].l,ask[i].r);
    			ask[i].l=t[ask[i].l];
    			ask[i].r=t[ask[i].r];
    		}
    		else if (ask[i].r==LCA)
    		{
    			ask[i].l=t[ask[i].l];
    			ask[i].r=t[ask[i].r];
    		}
    		else
    		{
    			if (t[ask[i].l]>t[ask[i].r]) swap(ask[i].l,ask[i].r);
    			ask[i].l=t[ask[i].l];
    			ask[i].r=s[ask[i].r];
    		}	
    	}
    	sort(ask+1,ask+1+m,cmp);
    	int l=1,r=0;
    	for (int i=1;i<=m;i++)
    	{
    		for (;l<ask[i].l;l++) maintain(dfn[l]);
    		for (;l>ask[i].l;l--) maintain(dfn[l-1]);
    		for (;r<ask[i].r;r++) maintain(dfn[r+1]);
    		for (;r>ask[i].r;r--) maintain(dfn[r]);
    		int x=dfn[l],y=dfn[r];
    		int LCA=lca(x,y);
    		if (LCA!=x && LCA!=y) add(LCA);
    		if (cnt[ask[i].b] && cnt[ask[i].a] && ask[i].a!=ask[i].b) ans[ask[i].id]=sum-1;
    			else ans[ask[i].id]=sum;
    		if (LCA!=x && LCA!=y) del(LCA);
    	}
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    BZOJ1006: [HNOI2008]神奇的国度
    弦图与区间图
    后缀自动机
    插头DP
    BZOJ3328: PYXFIB
    BZOJ2118: 墨墨的等式
    BZOJ3916: [Baltic2014]friends
    BZOJ1337: 最小圆覆盖
    BZOJ3784: 树上的路径
    代码模版
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998088.html
Copyright © 2011-2022 走看看