Description
Input
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
Solution
-
考虑暴力的根号算法,先将原树定为一颗有根树。
-
修改时先考虑其子节点,可以发现不同的权值最多有 m \sqrt m m 种(最坏情况是 1 , 2 , 3 , 4 … … 1,2,3,4…… 1,2,3,4……)
-
于是我们用一个链表存每个点的儿子节点不同种类的值及该值的个数。
-
对儿子节点的修改就是 O ( m ) O(\sqrt m) O(m) 的。
-
那么修改它的父亲节点,我们只需找其父亲的父亲,再改儿子就可以了。
-
这里涉及到如何 O ( 1 ) O(1) O(1) 快速查询一个点的现时权值,这个打两个标记就可以了:
-
若修改点是 x x x ,那么我们令 t a g 1 [ x ] + + , t a g 2 [ f a [ x ] ] + + tag1[x]++ , tag2[fa[x]]++ tag1[x]++,tag2[fa[x]]++ ,来表示修改情况。
-
那么一个点 y y y 的现时权值就是 t a g 1 [ f a [ y ] ] + t a g 2 [ y ] tag1[fa[y]]+tag2[y] tag1[fa[y]]+tag2[y] 。
-
于是我们也能在 O ( m ) O(\sqrt m) O(m) 的复杂度内完成其父亲节点的修改。
-
这个算法的时间复杂度上限为 O ( m m ) O(m\sqrt m) O(mm) ,但实际上远达不到上限。
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;
}