看到这个标题立刻想到:、
“绝地科学家,八倍不屏息啊,八百里外把头打啊...”
首先我们发现如果只考虑第二个操作,这棵树就是假的,我们可以直接莫队解决
如果考虑换根的话...可以把一个操作换成小于等于9个操作就可以了
当然怎么换,有一些非常恶心的分类讨论
嘤嘤嘤
YNOI 题是好题 但是要卡常 首先要fread & fwrite
然后需要wxh的莫队写法
然后要算一下分块大小
sqrt(q_size) -> (n / sqrt(q_size))
40 -> 100
嘤嘤嘤
#include<bits/stdc++.h> #define LL long long using namespace std; inline char nc() { static char buf[100000] , *p1 , *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ; } inline int read() { int ret = 0; char ch = nc(); while(!isdigit(ch)) ch = nc(); while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc(); return ret; } char pbuf[100000] , *pp = pbuf; inline void push(const char ch) { if(pp == pbuf + 100000) fwrite(pbuf , 1 , 100000 , stdout) , pp = pbuf; *pp ++ = ch; } inline void write(long long x) { static char sta[20]; int top = 0; if(!x) push('0'); while(x) sta[++top] = x % 10 ^ '0' , x /= 10; while(top) push(sta[top -- ]); push('\n'); } const int maxn = 100010; int n,m,rt; int qx; int a[maxn],vi[maxn]; int q_size; int first[maxn],to[maxn << 1],nx[maxn << 1],cnt; inline void add(int u,int v) { to[++cnt] = v; nx[cnt] = first[u]; first[u] = cnt; } inline void ins(int u,int v){add(u,v);add(v,u);} struct Q { int l,r,bl,id,opt; Q(){}; Q(int _l,int _r,int _id,int _opt){l = min(_l,_r),r = max(_l,_r),id = _id,opt = _opt;} bool operator < (const Q &b)const { if(bl == b.bl) { if(bl & 1) return r < b.r; return r > b.r; } return l < b.l; } }qs[maxn * 45]; int fa[maxn][23],dep[maxn],ind[maxn],oud[maxn],reh[maxn],dfn; inline void dfs(int x) { ind[x] = ++dfn;reh[dfn] = a[x]; for(int i=1;i<=22;i++) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(int i=first[x];i;i=nx[i]) { if(to[i] == fa[x][0])continue; dep[to[i]] = dep[x] + 1; fa[to[i]][0] = x; dfs(to[i]); }oud[x] = dfn; } LL ans[maxn * 5]; LL now;int cnt_x[maxn],cnt_y[maxn]; inline int go_anc(int x , int y) { int i; for(i = 22 ; ~i ; i -- ) if(dep[y] - dep[x] > (1 << i)) y = fa[y][i]; return y; } int xpos[10],ypos[10],opt_x[10],opt_y[10]; int main() { freopen("1.in","r",stdin); freopen("www.out","w",stdout); int tx,ty; n = read(),m = read(); for(int i=1;i<=n;i++)vi[i] = a[i] = read(); sort(vi + 1,vi + n + 1); for(int i=1;i<=n;i++)a[i] = lower_bound(vi + 1,vi + n + 1,a[i]) - vi; for(int i=2;i<=n;i++) { int u = read(),v = read(); ins(u,v); }dfs(rt = 1); //return 0; for(int i=1;i<=m;i++) { int t = read(),x = read(); if(t == 1){rt = x;continue;} int y = read(),z;q_size++; tx = ty = 0; if(x == rt) xpos[++tx] = n , opt_x[tx] = 1; else if(ind[rt] < ind[x] || ind[rt] > oud[x]) xpos[++tx] = oud[x] , opt_x[tx] = 1 , xpos[++tx] = ind[x] - 1 , opt_x[tx] = -1; else z = go_anc(x , rt) , xpos[++tx] = n , opt_x[tx] = 1 , xpos[++tx] = oud[z] , opt_x[tx] = -1 , xpos[++tx] = ind[z] - 1 , opt_x[tx] = 1; if(y == rt) ypos[++ty] = n , opt_y[ty] = 1; else if(ind[rt] < ind[y] || ind[rt] > oud[y]) ypos[++ty] = oud[y] , opt_y[ty] = 1 , ypos[++ty] = ind[y] - 1 , opt_y[ty] = -1; else z = go_anc(y , rt) , ypos[++ty] = n , opt_y[ty] = 1 , ypos[++ty] = oud[z] , opt_y[ty] = -1 , ypos[++ty] = ind[z] - 1 , opt_y[ty] = 1; for(int j=1;j<=tx;j++) for(int k=1;k<=ty;k++) if(xpos[j] && ypos[k]) qs[++qx] = Q(xpos[j] , ypos[k] , q_size , opt_x[j] * opt_y[k]); } int si = (int)(n / sqrt(qx)); for(int i=1;i<=qx;i++)qs[i].bl = (qs[i].l - 1) / si; sort(qs + 1,qs + qx + 1); int l = 0,r = 0; for(int i=1;i<=qx;i++) { while(l < qs[i].l){l++;now += cnt_y[reh[l]],cnt_x[reh[l]]++;} while(r < qs[i].r){r++;now += cnt_x[reh[r]],cnt_y[reh[r]]++;} while(l > qs[i].l){cnt_x[reh[l]]--;now -= cnt_y[reh[l]];l--;} while(r > qs[i].r){cnt_y[reh[r]]--;now -= cnt_x[reh[r]];r--;} ans[qs[i].id] += now * qs[i].opt; } for(int i=1;i<=q_size;i++)write(ans[i]); fwrite(pbuf , 1 , pp - pbuf , stdout); }