题意:
给定一棵树,对每个点 i ,统计树上面与其距离不超过
k 的点的个数,然后所有值求异或。 1≤N≤500000 , 1≤K≤10
思路:
暴力,开始想到了同样的思路,觉得暴力会挂的样子,没敢去写。。。
首先处理出 dp[i][j] 表示 i 节点子树中与
i 的距离 ≤j 的点的数目。对于每个节点统计答案,往上枚举距离在 k <script type="math/tex" id="MathJax-Element-512">k</script> 内的LCA,然后去统计另外一个满足条件的节点的数目,注意边界条件的处理,还有去重哦!!!
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define INF 0x3f3f3f3f
#define eps 1e-8
#define FI first
#define SE second
#define maxm 1000009
#define maxn 500009
using namespace std;
struct Edge{
int v,next;
}edge[maxm];
int head[maxn],tot,n,m,A,B;
int dp1[maxn][11],fa[maxn];
void init(){
memset(head,-1,sizeof(head));
tot = 0;
}
inline void addedge(int u,int v){
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u){
for(int i = 0;i <= m;i ++)
dp1[u][i]=0;
dp1[u][0] = 1;
int v;
for(int e = head[u];e != -1;e = edge[e].next){
v = edge[e].v;
fa[v] = u;
dfs(v);
for(int i = 0;i < m;i ++)
dp1[u][i+1] += dp1[v][i];
}
}
int main()
{
int tt;
scanf("%d",&tt);
while(tt --){
init();
scanf("%d%d%d%d",&n,&m,&A,&B);
for(int i = 2;i <= n;i ++){
int fa = (1LL*A*i+B)%(i-1)+1;
addedge(fa,i);
}
fa[1] = -1;
int ans = 0;
dfs(1);//得到i为子树里,距离为j的点的个数
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++)
dp1[i][j] += dp1[i][j-1];//得到i为子树里,距离<=j的点的个数
for(int i = 1;i <= n;i ++){
int val = dp1[i][m];//首先统计i子树中满足条件的点
int cnt = 1,cur = i;
//枚举LCA
while(cnt <= m && fa[cur] != -1){
val += dp1[fa[cur]][m-cnt];
if(m-cnt-1 >= 0)
val -= dp1[cur][m-cnt-1];//减去重复统计的
cnt ++;
cur = fa[cur];
}
ans = ans^val;
}
printf("%d\n",ans);
}
//system("pause");
return 0;
}