JZOJ 5984. 【北大2019冬令營模擬2019.1.1】仙人掌

Description

Description

Input

Input

Output

Output

Sample Input

5 10
1 2
2 3
2 4
3 5
1
5
2
4
3
5
4
2
3
1

Sample Output

2060

Data Constraint

Data Constraint

Solution

  • 考慮暴力的根號算法,先將原樹定爲一顆有根樹。

  • 修改時先考慮其子節點,可以發現不同的權值最多有 m\sqrt m 種(最壞情況是 1,2,3,41,2,3,4……

  • 於是我們用一個鏈表存每個點的兒子節點不同種類的值及該值的個數。

  • 對兒子節點的修改就是 O(m)O(\sqrt m) 的。

  • 那麼修改它的父親節點,我們只需找其父親的父親,再改兒子就可以了。

  • 這裏涉及到如何 O(1)O(1) 快速查詢一個點的現時權值,這個打兩個標記就可以了:

  • 若修改點是 xx ,那麼我們令 tag1[x]++,tag2[fa[x]]++tag1[x]++ , tag2[fa[x]]++ ,來表示修改情況。

  • 那麼一個點 yy 的現時權值就是 tag1[fa[y]]+tag2[y]tag1[fa[y]]+tag2[y]

  • 於是我們也能在 O(m)O(\sqrt m) 的複雜度內完成其父親節點的修改。

  • 這個算法的時間複雜度上限爲 O(mm)O(m\sqrt m) ,但實際上遠達不到上限。

Code

#include<cstdio>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=5e5+5,M=N*80,mo=1000109107;
int tot,sum;
int first[N],nex[N<<1],en[N<<1];
int first1[N],nex1[M],en1[M],w[M];
int fa[N],son[N],t1[N],t2[N];
inline int read()
{
	int X=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
inline void insert(int x,int y)
{
	nex[++tot]=first[x];
	first[x]=tot;
	en[tot]=y;
}
void dfs(int x)
{
	for(int i=first[x];i;i=nex[i])
		if(en[i]^fa[x])
		{
			fa[en[i]]=x;
			son[x]++;
			dfs(en[i]);
		}
}
int main()
{
	freopen("cactus.in","r",stdin);
	freopen("cactus.out","w",stdout);
	int n=read(),m=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		insert(x,y);
		insert(y,x);
	}
	dfs(1);
	fa[1]=n+1;
	son[n+1]=1;
	tot=0;
	for(int i=1;i<=n+1;i++)
	{
		nex1[++tot]=first1[i];
		first1[i]=tot;
		en1[tot]=0;
		w[tot]=son[i];
	}
	for(int j=1;j<=m;j++)
	{
		int x=read();
		for(int i=first1[x];i;i=nex1[i]) en1[i]++;
		int ans=0;
		if(x>1)
		{
			int y=fa[fa[x]],num=t2[fa[x]]+t1[y];
			for(int i=first1[y],last=0;i;last=i,i=nex1[i])
				if(en1[i]==num)
				{
					if(w[i]>1)
					{
						w[i]--;
						break;
					}
					if(i==first1[y])
					{
						first1[y]=nex1[i];
					}else
					{
						nex1[last]=nex1[i];
					}
					break;
				}
			num++;
			bool pd=false;
			for(int i=first1[y];i;i=nex1[i])
				if(en1[i]==num)
				{
					w[i]++;
					pd=true;
					break;
				}
			if(!pd)
			{
				nex1[++tot]=first1[y];
				first1[y]=tot;
				en1[tot]=num;
				w[tot]=1;
			}
			ans=num;
		}
		t1[x]++;
		t2[fa[x]]++;
		for(int i=first1[x];i;i=nex1[i])
			if(w[i]&1) ans^=en1[i];
		ans=ans*((LL)j*j%mo+j)%mo;
		sum=(sum+ans)%mo;
	}
	printf("%d",sum);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章