题目大意:给定一棵树,每个节点有一个颜色,多次询问某条路径上颜色数量,强制在线
正解是块状数组,强制在线莫队会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;
}
/*
アナタガ望ムノナラバ
犬ノヤウニ従顺ニ
纽ニ縄ニ锁ニ
缚ラレテアゲマセウ
*/
卡常数狗我操你。
总有一天我会用莫队算法卡过这道题的。