题目大意:给定一棵树,每个节点有一个颜色,多次询问某条路径上颜色数量,强制在线

正解是块状数组,强制在线莫队会TLE到死,想AC这道题的不用看了

如果朴素的跑树上莫队其实并不难- - 但是强制在线

因此我们可以考虑强制在线莫队算法

将树分成O(n^1/3)块,每块大小O(n^2/3)

记录每两块之间的答案、每种颜色的出现次数和哪些点被记录到了答案中

每次查询先找到两端点所在块的端点的答案,然后暴力用莫队转移即可

空间复杂度O(n^1/3)*O(n^1/3)*O(n)=O(n^5/3)

预处理时间复杂度O(n^1/3)*O(n^1/3)*O(n)=O(n^5/3)

单次询问时间复杂度O(n^2/3)


然后。。。被卡常数。。。明明本机只要不到11秒就能全部出解。。。BZ渣评测机怎么这么慢。。。

读入优化。。。寻址优化。。。short压内存。。。内嵌汇编强制inline。。。函数改成宏。。。倍增LCA改成RMQLCA。。。三分法修改块的大小。。。还有啥。。。bool改成bitset。。。随机数选根防卡。。。还特意去切了王室联邦练习树分块。。。最后还在结尾附加一段注释增强一下信仰。。。

从早上卡到现在。。。 加上昨天写的版本一共挂了七篇。。。整整七篇。。。。。。。。。。。。。。。。。。。。。

发个本地评测的图吧。。。 此题精神AC了。。。

BZOJ 2589 Spoj 10707 Count on a tree II 强制在线莫队算法(TLE)_块状树

我が生涯に、一片の悔いなし。。。。。

#include <bitset>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 40002
#define B 95
#define Change(x,f,v,ans) {  \
	if(v[x])                  \
	{                          \
		if(!--f[a[x]])          \
			--ans;               \
		v[x]=0;                   \
	}                              \
	else                            \
	{                                \
		if(!f[a[x]]++)                \
			++ans;                     \
		v[x]=1;                         \
	}                                    \
}
#define swap(x,y) {int t=x;x=y;y=t;}
using namespace std;
struct abcd{
	int to,next;
}table[M<<1];
int head[M],tot;

int n,m,b,cnt,last_ans;

int a[M],fa[M],dpt[M],log2[M<<1],min_dpt[M<<1][20],into[M];
int belong[M],root[M],stack[M],top;

unsigned short f[B*(B-1)/2*M+M];
bitset<M> v[B][B];
int ans[B][B],pos[B][B];

__inline__ __attribute__((always_inline)) void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void DFS(int x)
{
	static int T;
	int i,bottom=top;
	dpt[x]=dpt[fa[x]]+1;
	min_dpt[into[x]=++T][0]=x;
	for(i=head[x];i;i=table[i].next)
		if(table[i].to!=fa[x])
		{
			fa[table[i].to]=x;
			DFS(table[i].to);
			if(top-bottom>=b)
			{
				while(top!=bottom)
					belong[stack[top--]]=cnt;
				root[cnt++]=x;
			}
			min_dpt[++T][0]=x;
		}
	stack[++top]=x;
}
/*
__inline__ __attribute__((always_inline)) void Change(int x,unsigned short f[M],bitset<M> &v,int &ans)
{
	if(v[x])
	{
		if(!--f[a[x]])
			--ans;
	}
	else
	{
		if(!f[a[x]]++)
			++ans;
	}
	v[x]=!v[x];
}
*/
void Pretreatment(int x,int y,unsigned short f[M],bitset<M> &v,int &ans)
{
	if(dpt[x]<dpt[y])
		swap(x,y);
	while(dpt[x]>dpt[y])
	{
		Change(x,f,v,ans);
		x=fa[x];
	}
	while(x!=y)
	{
		Change(x,f,v,ans);
		Change(y,f,v,ans);
		x=fa[x];y=fa[y];
	}
}
__inline__ __attribute__((always_inline)) int Min(int x,int y)
{
	return dpt[x]<dpt[y]?x:y;
}
__inline__ __attribute__((always_inline)) int LCA(int x,int y)
{
	x=into[x];y=into[y];
	if(x>y) swap(x,y);
	int j=log2[y-x+1];
	return Min(min_dpt[x][j],min_dpt[y-(1<<j)+1][j]);
}
int Query(int x,int y)
{
	static unsigned short f[M];
	static bitset<M> v;
	static int tim1[M],tim2[M],T;++T;
	if(belong[x]>belong[y])
		swap(x,y);
	unsigned short *F=::f+pos[belong[x]][belong[y]];
	bitset<M> &V=::v[belong[x]][belong[y]];
	int ans=::ans[belong[x]][belong[y]];
	int l=root[belong[x]],r=root[belong[y]];

	unsigned short temp,a_t,lca=LCA(l,x);
	for(int temp=x;temp!=lca;temp=fa[temp])
	{
		a_t=a[temp];
		if(tim1[a_t]!=T)
			tim1[a_t]=T,f[a_t]=F[a_t];
		if(tim2[temp]!=T)
			tim2[temp]=T,v[temp]=V[temp];
		Change(temp,f,v,ans);
	}
	for(temp=l;temp!=lca;temp=fa[temp])
	{
		a_t=a[temp];
		if(tim1[a_t]!=T)
			tim1[a_t]=T,f[a_t]=F[a_t];
		if(tim2[temp]!=T)
			tim2[temp]=T,v[temp]=V[temp];
		Change(temp,f,v,ans);
	}

	lca=LCA(r,y);
	for(temp=y;temp!=lca;temp=fa[temp])
	{
		a_t=a[temp];
		if(tim1[a_t]!=T)
			tim1[a_t]=T,f[a_t]=F[a_t];
		if(tim2[temp]!=T)
			tim2[temp]=T,v[temp]=V[temp];
		Change(temp,f,v,ans);
	}
	for(temp=r;temp!=lca;temp=fa[temp])
	{
		a_t=a[temp];
		if(tim1[a_t]!=T)
			tim1[a_t]=T,f[a_t]=F[a_t];
		if(tim2[temp]!=T)
			tim2[temp]=T,v[temp]=V[temp];
		Change(temp,f,v,ans);
	}

	temp=LCA(x,y);
	a_t=a[temp];
	if(tim1[a_t]!=T)
		tim1[a_t]=T,f[a_t]=F[a_t];
	if(tim2[temp]!=T)
		tim2[temp]=T,v[temp]=V[temp];
	Change(temp,f,v,ans);

	return ans;
}
namespace IStream{  
    const int L=1<<15;  
    char buffer[L],*S,*T;
    char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;  
    }  
    int Get_Int()  
    {  
        char c;  
        int re=0;  
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());  
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
        return re;  
    }  
}
class OStream{  
    private:  
        static const int L=1<<15;  
        char stack[20];int top;  
        char buffer[L],*S;  
    public:  
        OStream()  
        {  
            S=buffer;  
        }  
        void Put_Int(int x,bool flag)  
        {  
            if(flag) stack[++top]='\n';  
            if(!x) stack[++top]='0';  
            else while(x)  
                stack[++top]=x%10+'0',x/=10;  
            while(top)  
            {  
                if(S==buffer+L-1)  
                {  
                    //fwrite(buffer,1,S-buffer,stdout);  
                    printf("%s",buffer);
					S=buffer;  
                }  
                *S++=stack[top--];
            }  
        }  
        ~OStream()
        {  
            //fwrite(buffer,1,S-buffer,stdout);
            *S=0;printf("%s",buffer);
        }  
}os;
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("2589.in","r",stdin);
	freopen("2589.out","w",stdout);
	#endif
	
	static pair<int,int*> b[M];
	int i,j,x,y;

	cin>>n>>m;
	::b=420;

	for(i=1;i<=n;i++)
		b[i].first=IStream::Get_Int(),b[i].second=&a[i];
	sort(b+1,b+n+1);
	for(i=1;i<=n;i++)
	{
		static int tot=0;
		if(i==1||b[i].first!=b[i-1].first)
			++tot;
		*b[i].second=tot;
	}

	for(i=1;i<n;i++)
	{
		x=IStream::Get_Int();
		y=IStream::Get_Int();
		Add(x,y);Add(y,x);
	}
	int r=6854654%n+1;
	DFS(r);
	if(!cnt) root[cnt++]=r;
	while(top)
		belong[stack[top--]]=cnt-1;
	log2[0]=-1;
	for(i=1;i<=n-1<<1;i++)
		log2[i]=log2[i>>1]+1;
	for(j=1;j<=log2[n-1<<1];j++)
		for(i=1;i+(1<<j)-1<=n-1<<1;i++)
			min_dpt[i][j]=Min(min_dpt[i][j-1],min_dpt[i+(1<<j-1)][j-1]);
			

	for(i=0;i<cnt;i++)
		for(j=i+1;j<cnt;j++)
		{
			static int T;
			pos[i][j]=(++T)*M;
			if(j==i+1)
				Pretreatment(root[i],root[j],f+pos[i][j],v[i][j],ans[i][j]);
			else
			{
				memcpy(f+pos[i][j],f+pos[i][j-1],sizeof(unsigned short)*M);
				v[i][j]=v[i][j-1];
				ans[i][j]=ans[i][j-1];
				Pretreatment(root[j],root[j-1],f+pos[i][j],v[i][j],ans[i][j]);
			}
		}

	for(i=1;i<=m;i++)
	{
		x=IStream::Get_Int()^last_ans;
		y=IStream::Get_Int();
		os.Put_Int(last_ans=Query(x,y),i<m);
	}
	
	/*
	os.Put_Int(2147483647,true);
	sort(root,root+cnt);
	for(i=0;i<cnt;i++)
		os.Put_Int(root[i],true);
	*/
	
	return 0;
}
/*
アナタガ望ムノナラバ
犬ノヤウニ従顺ニ
纽ニ縄ニ锁ニ
缚ラレテアゲマセウ
*/


卡常数狗我操你。

总有一天我会用莫队算法卡过这道题的。