【BZOJ】【3757】苹果树
树分块
orz HZWER
http://hzwer.com/5259.html不知为何我原本写的倍增求LCA给WA了……学习了HZWER的倍增新姿势~
树上分块的转移看vfk博客的讲解吧……(其实是先指向hzwer博客,再跳转vfk和KuribohG……)
vfk讲的很详细,重点就在于转移的时候无视lca,只有在计算答案的时候临时加进来lca,算完答案再把lca去掉。
1 /************************************************************** 2 Problem: 3757 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:17180 ms 7 Memory:17716 kb 8 ****************************************************************/ 9 10 //BZOJ 3757 11 #include<cmath> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 using namespace std; 21 void read(int &v){ 22 v=0; int sign=1; char ch=getchar(); 23 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 24 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 25 v*=sign; 26 } 27 #define debug 28 /******************tamplate*********************/ 29 const int N=100010; 30 int head[N],to[N],next[N],cnt; 31 void add(int x,int y){ 32 to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; 33 to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; 34 } 35 /*******************edge************************/ 36 int n,m,color[N],root; 37 int B,belong[N],st[N],top,tot,deep[N]; 38 int fa[N][20],bin[25]; 39 void dfs(int x){ 40 int bottom=top; 41 for(int i=1;i<=16;i++) 42 if(deep[x]>=bin[i]) 43 fa[x][i]=fa[fa[x][i-1]][i-1]; 44 else break; 45 for(int i=head[x];i;i=next[i]) 46 if (to[i]!=fa[x][0]){ 47 fa[to[i]][0]=x; 48 deep[to[i]]=deep[x]+1; 49 dfs(to[i]); 50 if (top-bottom>=B){ 51 ++tot; 52 while(top!=bottom) 53 belong[st[top--]]=tot; 54 } 55 } 56 st[++top]=x; 57 } 58 int LCA(int x,int y){ 59 if (deep[x]<deep[y]) swap(x,y); 60 int t=deep[x]-deep[y]; 61 for(int i=0;bin[i]<=t;i++) 62 if (t&bin[i]) x=fa[x][i]; 63 D(i,16,0) 64 if(fa[x][i]!=fa[y][i]) 65 x=fa[x][i],y=fa[y][i]; 66 if(x==y) return x; 67 return fa[x][0]; 68 } 69 /*******************dfs&&LCA********************/ 70 struct ques{ 71 int x,y,a,b,num; 72 bool operator < (const ques &now)const{ 73 if (belong[x]==belong[now.x]) return belong[y]<belong[now.y]; 74 else return belong[x]<belong[now.x]; 75 } 76 }Q[N]; 77 78 int num[N],ans=0,ANS[N]; 79 bool used[N]; 80 inline void work(int x){ 81 if(!used[x]){ 82 num[color[x]]++;used[x]=1; 83 if(num[color[x]]==1) ans++; 84 } 85 else{ 86 num[color[x]]--;used[x]=0; 87 if(num[color[x]]==0) ans--; 88 } 89 } 90 91 void Xor(int x,int y){ 92 int lca=LCA(x,y); 93 while(x!=lca) {work(x); x=fa[x][0];} 94 while(y!=lca) {work(y); y=fa[y][0];} 95 } 96 97 int main(){ 98 bin[0]=1; F(i,1,20) bin[i]=bin[i-1]<<1; 99 100 read(n); read(m); 101 B=sqrt(n); 102 F(i,1,n) read(color[i]); 103 int x,y; 104 F(i,1,n){ 105 read(x); read(y); 106 if (x==0) root=y; 107 if (y==0) root=x; 108 add(x,y); 109 } 110 dfs(root); 111 tot++; 112 while(top)belong[st[top--]]=tot; 113 114 int a,b; 115 F(i,1,m){ 116 read(x); read(y); read(a); read(b); 117 Q[i]=(ques){x,y,a,b,i}; 118 } 119 sort(Q+1,Q+m+1); 120 //转移的时候不考虑LCA,查答案的时候临时算进来,计算完答案后再把LCA删掉 121 int lca=(LCA(Q[1].x,Q[1].y)); 122 Xor(Q[1].x,Q[1].y); 123 work(lca); 124 ANS[Q[1].num]=ans; 125 if (num[Q[1].a]!=0 && num[Q[1].b]!=0 && Q[1].a!=Q[1].b) ANS[Q[1].num]--; 126 work(lca); 127 F(i,2,m){ 128 Xor(Q[i-1].x,Q[i].x); 129 Xor(Q[i-1].y,Q[i].y); 130 lca=LCA(Q[i].x,Q[i].y); 131 work(lca); 132 ANS[Q[i].num]=ans; 133 if(num[Q[i].a]!=0 && num[Q[i].b]!=0 && Q[i].a!=Q[i].b) ANS[Q[i].num]--; 134 work(lca); 135 } 136 F(i,1,m) printf("%d\n",ANS[i]); 137 return 0; 138 }
3757: 苹果树
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 632 Solved: 223
[Submit][Status][Discuss]
Description
神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个到n之间的正整数来表示一种颜色。树上一共有n个苹果。每个苹果都被编了号码,号码为一个1到n之间的正整数。我们用0代表树根。只会有一个苹果直接根。
有许许多多的人来神犇家里膜拜神犇。可神犇可不是随便就能膜拜的。前来膜拜神犇的人需要正确回答一个问题,才能进屋膜拜神犇。这个问题就是,从树上编号为u的苹果出发,由树枝走到编号为v的苹果,路径上经过的苹果一共有多少种不同的颜色(包括苹果u和苹果v的颜色)?不过神犇注意到,有些来膜拜的人患有色盲症。具体地说,一个人可能会认为颜色a就是颜色b,那么他们在数苹果的颜色时,如果既出现了颜色a的苹果,又出现了颜色b的苹果,这个人只会算入颜色b,而不会把颜色a算进来。
神犇是一个好人,他不会强人所难,也就会接受由于色盲症导致的答案错误(当然答案在色盲环境下也必须是正确的)。不过这样神犇也就要更改他原先数颜色的程序了。虽然这对于神犇来说是小菜一碟,但是他想考验一下你。你能替神犇完成这项任务吗?
Input
输入第一行为两个整数n和m,分别代表树上苹果的个数和前来膜拜的人数。
接下来的一行包含n个数,第i个数代表编号为i的苹果的颜色Coli。
接下来有n行,每行包含两个数x和y,代表有一根树枝连接了苹果x和y(或者根和一个苹果)。
接下来有m行,每行包含四个整数u、v、a和b,代表这个人要数苹果u到苹果v的颜色种数,同时这个人认为颜色a就是颜色b。如果a=b=0,则代表这个人没有患色盲症。
Output
输出一共m行,每行仅包含一个整数,代表这个人应该数出的颜色种数。
Sample Input
5 3
1 1 3 3 2
0 1
1 2
1 3
2 4
3 5
1 4 0 0
1 4 1 3
1 4 1 2
1 1 3 3 2
0 1
1 2
1 3
2 4
3 5
1 4 0 0
1 4 1 3
1 4 1 2
Sample Output
2
1
2
1
2
HINT
0<=x,y,a,b<=N
N<=50000
1<=U,V,Coli<=N