【BZOJ4940】【YNOI2016】这是我自己的发明
阅读此篇文章前请先跟我大喊三声:dllxl!dllxl!dllxl!
咳咳。
题意:
Description
Input
Output
题解:
非常不推荐去阅读原题面(看完题面就知道出题人系列)
众所周知,云南省选全是毒瘤数据结构题
其实这是一道BZOJ二合一。。。BZOJ3083 遥远的国度+BZOJ5016一个简单的询问(题解咕咕咕中)
如果没有换根操作,先来考虑如何处理询问(BZOJ5016):
首先按照dfs序把问题转化到序列上,询问就变成了选取序列中的两个区间,答案即为在两个区间中出现过的每个数分别在两个区间出现次数的乘积;
用公式表达就是:
$ans=\sum\limits_{x=1}^{\infty}sum(l_1,r_1,x)\times sum(l_2,r_2,x)$,其中$sum(l,r,x)$表示数字$x$在区间$[l,r]$中出现的次数。
这个东西。。。不好处理啊。。。
一般这种多组询问且不知所云不好维护的东西都会想到分块,然后快(du)乐(liu)莫队?
那就推一推前缀形式:
$ans=\sum\limits_{x=1}^{\infty}sum(l_1,r_1,x)\times sum(l_2,r_2,x)$
$=\sum\limits_{x=1}^{\infty}(sum(1,r_1,x)-sum(1,l_1-1,x))\times(sum(1,r_2,x)-sum(1,l_2-1,x))$
$=\sum\limits_{x=1}^{\infty}sum(1,r_1,x)·sum(1,r_2,x)-sum(1,r_1,x)·sum(1,l_2-1,x)-sum(1,l_1-1,x)·sum(1,r_2,x)+sum(1,l_1-1,x)·sum(1,l_2-1,x)$
设$f(n,m)=\sum\limits_{x=1}^{\infty}sum(1,n,x)·sum(1,m,x)$
则$ans=f(r_1,r_2)-f(r_1,l_2-1)-f(l_1-1,r_2)+f(l_1-1,l_2-1)$
所以可以询问一拆四然后直接上莫队……
然后看换根(BZOJ3083):
数据结构学傻了->这题一定能用LCT!
啊LCT不能维护子树信息……
数据结构学傻了*2->换根一定能用树剖记录!
啊dfs序会变然后就不能维护了……
因此我们要大力分类讨论:
设根为root,所求子树的根为rt
1.root==rt:continue;
2.root不在rt的子树中:即换根后rt子树中的dfs顺序不会变,所以直接遍历即可;
3.rt在root的子树中:
分析此时的dfs顺序:应该是从root开始,访问到rt的子节点中是root的祖先的节点(记为点F),再访问rt,最后才是其它节点。那么在rt之前访问到的只有F的子树,其它的都是rt子树中的节点。众所周知子树dfs序连续,所以查询rt此时的子树就相当于查询线段树中$[1,l-1]$和$[r+1,n]$中的节点。
所以只有第三种情况特殊求一个F,然后直接维护即可;
求点F可以用树上倍增,当然在bzoj3083原题中是树剖就可以用树剖找。
然后就可以喜闻乐见的把两题拼在一起,码码码~
要注意的是由于换根的三种情况比较麻烦,莫队要拆成九个询问,于是常数upup
最后的时间复杂度是$O(n\sqrt{m})$,原题由于友(du)善(liu)出题人lxl的无私馈赠因此要大力卡常+调参+fread、fwrite才能过,而小视野非常良心的开了两倍时限,于是就开心过掉啦~
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 //typedef long long ll;
11 struct edge{
12 int v,next;
13 }a[200001];
14 struct nd{
15 int x,id;
16 friend bool operator <(nd a,nd b){
17 return a.x<b.x;
18 }
19 }s[200001];
20 int BLK,n,m,op,u,v,l,r,rt=1,tot=0,tim=0,cnt=0,tmp=0,head[200001],ans[500001],pos[200001],cl[200001],ll[200001],rr[200001],num[200001],in[200001],out[200001],dep[200001],fa[200001][20];
21 bool isans[500001];
22 struct task{
23 int l,r,op,id;
24 friend bool operator <(task a,task b){
25 return pos[a.l]==pos[b.l]?pos[a.r]<pos[b.r]:pos[a.l]<pos[b.l];
26 }
27 }t[4500001];
28 void add(int u,int v){
29 a[++tot].v=v;
30 a[tot].next=head[u];
31 head[u]=tot;
32 }
33 void dfs(int u,int ff,int dpt){
34 in[u]=++tim;
35 dep[u]=dpt;
36 fa[u][0]=ff;
37 for(int i=1;i<=19;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
38 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
39 int v=a[tmp].v;
40 if(v!=ff){
41 dfs(v,u,dpt+1);
42 }
43 }
44 out[u]=tim;
45 }
46 /*int lca(int u,int v){
47 if(dep[u]<dep[v])swap(u,v);
48 int l=dep[u]-dep[v];
49 for(int i=19;i>=0;i--){
50 if((1<<i)&l)u=fa[u][i];
51 }
52 if(u==v)return u;
53 for(int i=19;i>=0;i--){
54 if(fa[u][i]!=fa[v][i]){
55 u=fa[u][i],v=fa[v][i];
56 }
57 }
58 return fa[u][0];
59 }*/
60 int get(int u){
61 return (dep[u]<dep[rt]&&in[u]<=in[rt]&&in[rt]<=out[u])?u:rt;
62 }
63 int getfa(int u,int l){
64 for(int i=19;i>=0;i--){
65 if((1<<i)&l)u=fa[u][i];
66 }
67 return u;
68 }
69 void mv1l(int x){
70 tmp+=rr[cl[x]];
71 ll[cl[x]]++;
72 }
73 void mv2l(int x){
74 tmp-=rr[cl[x]];
75 ll[cl[x]]--;
76 }
77 void mv1r(int x){
78 tmp+=ll[cl[x]];
79 rr[cl[x]]++;
80 }
81 void mv2r(int x){
82 tmp-=ll[cl[x]];
83 rr[cl[x]]--;
84 }
85 int main(){
86 memset(head,-1,sizeof(head));
87 memset(isans,0,sizeof(isans));
88 scanf("%d%d",&n,&m);
89 BLK=(int)sqrt(n);
90 for(int i=1;i<=n;i++)pos[i]=(i-1)/BLK+1;
91 for(int i=1;i<=n;i++){
92 scanf("%d",&s[i].x);
93 s[i].id=i;
94 }
95 for(int i=1;i<n;i++){
96 scanf("%d%d",&u,&v);
97 add(u,v);
98 add(v,u);
99 }
100 dfs(1,0,1);
101 sort(s+1,s+n+1);
102 for(int i=1;i<=n;i++){
103 if(s[i].x!=s[i-1].x)cnt++;
104 cl[in[s[i].id]]=cnt;
105 }
106 cnt=0;
107 for(int i=1;i<=m;i++){
108 scanf("%d%d",&op,&u);
109 if(op==1)rt=u;
110 else{
111 scanf("%d",&v);
112 isans[i]=true;
113 if(u==v&&u==rt){
114 t[++cnt]=(task){n,n,1,i};
115 continue;
116 }
117 if(u!=v&&v==rt)swap(u,v);
118 int fu=get(u),fv=get(v);
119 if(u!=v&&u==rt){
120 if(fv==v){
121 v=getfa(rt,dep[rt]-dep[v]-1);
122 t[++cnt]=(task){n,in[v]-1,1,i};
123 t[++cnt]=(task){n,n,1,i};
124 t[++cnt]=(task){n,out[v],-1,i};
125 }else{
126 t[++cnt]=(task){n,out[v],1,i};
127 t[++cnt]=(task){n,in[v]-1,-1,i};
128 }
129 continue;
130 }
131 if(fu==u&&fv!=v){
132 swap(u,v);
133 swap(fu,fv);
134 }
135 if(fu!=u&&fv!=v){
136 t[++cnt]=(task){out[u],out[v],1,i};
137 t[++cnt]=(task){out[u],in[v]-1,-1,i};
138 t[++cnt]=(task){in[u]-1,in[v]-1,1,i};
139 t[++cnt]=(task){in[u]-1,out[v],-1,i};
140 }else if(fu!=u&&fv==v){
141 v=getfa(rt,dep[rt]-dep[v]-1);
142 t[++cnt]=(task){out[u],in[v]-1,1,i};
143 t[++cnt]=(task){out[u],n,1,i};
144 t[++cnt]=(task){out[u],out[v],-1,i};
145 t[++cnt]=(task){in[u]-1,in[v]-1,-1,i};
146 t[++cnt]=(task){in[u]-1,n,-1,i};
147 t[++cnt]=(task){in[u]-1,out[v],1,i};
148 }else{
149 u=getfa(rt,dep[rt]-dep[u]-1);
150 v=getfa(rt,dep[rt]-dep[v]-1);
151 t[++cnt]=(task){n,in[v]-1,1,i};
152 t[++cnt]=(task){n,n,1,i};
153 t[++cnt]=(task){n,out[v],-1,i};
154 t[++cnt]=(task){out[u],in[v]-1,-1,i};
155 t[++cnt]=(task){out[u],n,-1,i};
156 t[++cnt]=(task){out[u],out[v],1,i};
157 t[++cnt]=(task){in[u]-1,in[v]-1,1,i};
158 t[++cnt]=(task){in[u]-1,n,1,i};
159 t[++cnt]=(task){in[u]-1,out[v],-1,i};
160 }
161 }
162 }
163 sort(t+1,t+cnt+1);
164 l=t[1].l,r=t[1].r;
165 for(int i=1;i<=l;i++)ll[cl[i]]++;
166 for(int i=1;i<=r;i++){
167 rr[cl[i]]++;
168 tmp+=ll[cl[i]];
169 }
170 ans[t[1].id]+=tmp*t[1].op;
171 for(int i=2;i<=cnt;i++){
172 while(l<t[i].l)mv1l(++l);
173 while(l>t[i].l)mv2l(l--);
174 while(r<t[i].r)mv1r(++r);
175 while(r>t[i].r)mv2r(r--);
176 ans[t[i].id]+=tmp*t[i].op;
177 }
178 for(int i=1;i<=m;i++){
179 if(isans[i])printf("%d\n",ans[i]);
180 }
181 return 0;
182 }