P3604 美好的每一天

记得不久前畜牧给我口糊了一道题目。给定一棵树,每条边有一个权值,求所有路径上边的异或和的和。做法是用f[i][j][0]、f[i][j][1]表示第i个点,子树中路径的异或和的第j个二进制位为0、1的个数,然后大力dp就可以了。

看到这题的第一反应是用O(knlogn)的线段树合并。再加上这是一道关于异或和的题目,很容易就和畜牧说的题联系在了一起,然后就能把这题A掉了——吗?

显然不是,应该是然后我拼命的往这个方向思考,荒废了一下午的时光。

上面的好像全是废话,没错,所以它们被我划掉了。这个故事告诉我们划掉的话就不要去看了233(包括这句话)。

题解告诉我们,这题是道莫队题。(讲道理做这道题前我根本没听说过这个算法)

膜队要求能从[l,r]快速转移到[l,r+1](这里只举这个例子)。蒟蒻表示懵逼。蒟蒻不知道如何取出一段区间的所有后缀区间。膜了数小时的题解后,后知后觉的蒟蒻才知道:

先设这段后缀区间异或和为S。

整段区间的异或和可以用前缀和预处理。设为a。

用d表示S对应的前缀(从第一个数开始),使d^S=a。

符合条件的区间满足S=1<

<=>d^a=1<

<=>d=a^1<

这样子枚举就容易了。

然而我的代码自带神秘常数,怎么卡都只有70分。于是决定假装已经A过这题了。

#include
#include
#include
#include
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define us unsigned short
#define db double
#define ldb long double
#define pii pair
#define mkp make_pair
#define X first
#define Y second
const int N=60005;
pii qu[N];char str[N];
int n,m,s,t,sa[N],mo[N],a[N],S[N],sum,ans[N];us cnt[70000000];
bool cmp(int x,int y){
    return mo[qu[x].X]==mo[qu[y].X]?qu[x].Yv;sub(S[y--]));
        for(;x>u;add(S[(--x)-1]));
        for(;x

你可能感兴趣的:(luogu,*unsolved)