noip模拟赛(一)魔法树
魔法树
(mahou.pas/c/cpp)
【问题描述】
魔法使moreD在研究一棵魔法树。
魔法树顾名思义,这货是一棵树,奇葩的是魔法树上的每一条边都拥有一个魔法属性,如果不那么奇葩就不是moreD的魔法树了。
魔法使moreD在研究这棵魔法树的方法比较奇葩,每一次他会选择一条路径施法。
这个魔法是moreD的看家本领,叫元素剥离。施法过程是这样的:首先,moreD将把他的宠物通灵到魔法树上选定路径的一端,通灵不需要魔法值。初始时,宠物不拥有任何属性。
宠物会在moreD的指使下沿着路径走到另一个端点。在走过树上的边时。若该宠物已经拥有该边的属性,该宠物就会自己施法,使用当前边的属性,帮自身把相同的属性剥离,剥离完成后,宠物自身便不再带有该属性;否则,宠物会吸收该属性,即让自身拥有该属性。
宠物完成自己的旅途后,moreD要对宠物进行回收。回收时,若moreD的宠物不带有属性,则moreD需要使用1点魔法值。否则moreD使用的魔法值将是宠物剩下的属性所需剥离魔法值的积,以此来帮助自己的宠物剥离剩下的属性。
moreD想知道,对于每条选定的路径,moreD需要的魔法值数额对100,000,007取mod后的值是多少?
【输入格式】
输入第一行包含两个整数N,Q,K,表示魔法树的大小,询问数以及属性的数量。
接下来N-1行,每行表示一条魔法树上的边,ai,bi,ci。表示一条连接ai,bi两个点的边带有属性ci.
接下来一行,K个整数表示对于剥离每种属性所需的魔法值Cost i。
接下来Q行,每行一组询问,pi,qi表示moreD选定的施法路径。
【输出格式】
对于每组数据输出一行,表示该组询问的答案。
【输入样例】
5 4 3
1 2 2
1 5 3
2 3 2
2 4 1
1 2 3
3 5
1 3
4 5
4 4
【输出样例】
3
1
6
1
【数据范围】
对于前40%的数据 N,Q≤1,000
对于前80%的数据N≤100,000,Q≤40,000
对于100%的数据N,Q≤500,000 1≤ci≤K≤20 1≤ai,bi,pi,qi≤N Cost i≤100,000,000
对于所有奇数点的数据满足所有pi=1。
【题解】
- lca的处理:可以将节点1作为根节点,用bfs作预处理,用倍增法求lca。
- 魔法属性的处理:将属性编号转化成2的非负整数次幂(即,将第几编号转化为二进制的第几位),将lca最短路径上的所有属性压缩成一个int型整数,以异或计算将根到该节点的所有路径上的属性压缩到该节点的目标数组中。
- 属性操作:利用异或计算相同为0不同为1的性质,将要求lca的a、b两节点的数组值进行异或计算就可以得出a到b路径上的所有属性;需要累加时,取出异或计算的结果的每一位,若为1,则该位代表的位的属性就累乘。
- 注意:需要声明乘积变量为long long类型。
#include<stdio.h> #include<stdlib.h> using namespace std; static int bin[21],root=1; void make_bin() { bin[0]=0; bin[1]=1; for(int i=2;i<=20;i++) bin[i]=bin[i-1]<<1; } inline int read() { int x=0,c=getchar(),f=1; while(c<48||c>57){if(c=='-')f=-1;c=getchar();} while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x*f; } int n,q,k,m,cost[500001]; int v[1000001],first[1000001],nxt[1000001],magic[1000001]; bool vis[500001]; int qq[500101],f[1000001]; void Link(int x,int y,int z) { v[++m]=y; nxt[m]=first[x]; first[x]=m; magic[m]=z; } void bfs() { int head=0,tail=1; qq[head]=root; while(head^tail){ int now=qq[head++]; for(int i=first[now];i;i=nxt[i]) if(!vis[v[i]]){ vis[v[i]]=true; f[v[i]]=f[now]^bin[magic[i]]; qq[tail++]=v[i]; } } } int main() { make_bin(); freopen("mahou.in","r",stdin); freopen("mahou.out","w",stdout); n=read(),q=read(),k=read(); for(int i=1;i<=n-1;i++){ int x=read(),y=read(),z=read(); Link(x,y,z); Link(y,x,z); } bfs(); for(int i=1;i<=k;i++) cost[i]=read(); while(q--){ int pi=read(),qi=read(); int t=f[pi]^f[qi]; long long mul=1; for(int i=1;i<=k;i++,t>>=1){ if(!t)break; if(t&1)mul=((long long)mul*cost[i])%100000007; } printf("%I64d\n",mul); } fclose(stdin); fclose(stdout); return 0; } /* 5 4 3 1 2 2 1 5 3 2 3 2 2 4 1 1 2 3 3 5 1 3 4 5 4 4 */