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

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

正解是块状数组,强制在线莫队会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了。。。

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

#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;
}
/*
アナタガ望ムノナラバ
犬ノヤウニ従顺ニ
纽ニ縄ニ锁ニ
缚ラレテアゲマセウ
*/

卡常数狗我操你妈。

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

时间: 2024-11-09 10:44:48

BZOJ 2589 Spoj 10707 Count on a tree II 强制在线莫队算法(TLE)的相关文章

SPOJ COT2 Count on a tree II(树上莫队)

题目链接:http://www.spoj.com/problems/COT2/ You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perfrom the following operation: u v : ask for how many different integers that repr

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字

Count on a tree II(树上莫队)

Count on a tree II(luogu) Description 题目描述 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. 输入格式 第一行有两个整数n和m(n=40000,m=100000). 第二行有n个整数.第i个整数表示第i个节点表示的整数. 在接下来的n-1行中,每行包含两个整数u v,描述一条边(u,v). 在接下来的m行中,每一行包含两个整数u v,询问u到v的路径上有多少个不同的整数. 输出格式 对于每个询问,输出结果. Solutio

bzoj2589: Spoj 10707 Count on a tree II

Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v),表示一组询问. 数据范围是N<=40000 M<=100000 点权在int范围内

SPOJ10707 COT2 - Count on a tree II 【树上莫队】

题目分析: 考虑欧拉序,这里的欧拉序与ETT欧拉序的定义相同而与倍增LCA不同.然后不妨对于询问$u$与$v$让$dfsin[u] \leq dfsin[v]$,这样对于u和v不在一条路径上,它们可以改成询问$dfsin[u]$到$dfsin[v]$.否则改成$dfsout[u]$到$dfsin[v]$,并加上LCA上的影响,如果在询问过程中没有加入就加入,否则删除. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问.

bzoj 2588: Spoj 10628. Count on a tree LCA+主席树

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一

BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp