题目描述

您正在打galgame,然后突然家长进来了,于是您假装在写数据结构题:

给一个树,n 个点,有点权,初始根是 1。

m 个操作,每次操作:

1.将树根换为 x。

2.给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等,ans++,求 ans。

题解

  lxl的大毒瘤题名不虚传

  顺便先膜一下gxz大佬再说(毕竟像我这种菜鸡根本想不出这么巧的方法)->这里

  首先,如果没有换根的话,那么可以直接把子树当成dfs序上的一段区间来做,那么只要把询问给拆成好几个询问,然后直接用莫队就可以了

  然后考虑换根要怎么解决呢?可以参考【bzoj3083】遥远的国度,把子树变成原来的dfs序中的最多两段区间

  然后考虑块的大小,大佬说这题卡常,得把块的大小调成$\frac{n}{\sqrt{m}}*2$,否则会被卡,然而亲测不用乘2也能过……虽然跑得稍微慢了点

  顺带提一句,这里的莫队范围是$(1,x)$而不是$(l,r)$(因为是把询问写成了前缀和相减的形式),当初刚看到的时候没看懂还写错了……

 //minamoto
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=;
int a[N],b[N],head[N],Next[N<<],ver[N<<],tot;
int dep[N],ls[N],rs[N],son[N],sz[N],top[N],fa[N],cnt;
int vx[],ox[],tx,vy[],oy[],ty,cx[N],cy[N],w[N],px,py;
ll ans[N*],now;
int n,m,rt,cq,num=;
struct node{
int l,r,rt,id,opt;
node(){}
node(int L,int R,int Id,int Opt){l=min(L,R),r=max(L,R),id=Id,opt=Opt;}
bool operator<(const node &a)const {return rt == a.rt ? r < a.r : l < a.l;}
//inline bool operator <(const node &b)const{return rt==b.rt?rt&1?r<b.r:r>b.r:rt<b.rt;}
}q[N*];
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
}
void dfs1(int u){
sz[u]=,dep[u]=dep[fa[u]]+;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]){
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int t){
top[u]=t,ls[u]=++cnt,w[cnt]=a[u];
if(son[u]){
dfs2(son[u],t);
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
rs[u]=cnt;
}
inline int find(int t,int u){
while(top[u]!=top[t]){
if(fa[top[u]]==t) return top[u];
u=fa[top[u]];
}
return son[t];
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),m=read();
for(int i=;i<=n;++i) a[i]=b[i]=read();
sort(b+,b++n);
for(int i=;i<=n;++i) a[i]=lower_bound(b+,b++n,a[i])-b;
for(int i=;i<n;++i){
int u=read(),v=read();add(u,v);
}
dfs1(),dfs2(,);
for(int i=;i<=m;++i){
int op=read(),x=read(),y,z;
if(op&) rt=x;
else{
y=read(),++cq;
tx=ty=;
if(x==rt) vx[++tx]=n,ox[tx]=;
else if(ls[rt]<ls[x]||ls[rt]>rs[x]) vx[++tx]=rs[x],ox[tx]=,vx[++tx]=ls[x]-,ox[tx]=-;
else z=find(x,rt),vx[++tx]=n,ox[tx]=,vx[++tx]=rs[z],ox[tx]=-,vx[++tx]=ls[z]-,ox[tx]=;
if(y==rt) vy[++ty]=n,oy[ty]=;
else if(ls[rt]<ls[y]||ls[rt]>rs[y]) vy[++ty]=rs[y],oy[ty]=,vy[++ty]=ls[y]-,oy[ty]=-;
else z=find(y,rt),vy[++ty]=n,oy[ty]=,vy[++ty]=rs[z],oy[ty]=-,vy[++ty]=ls[z]-,oy[ty]=;
for(int j=;j<=tx;++j)
for(int k=;k<=ty;++k)
if(vx[j]&&vy[k])
q[++num]=node(vx[j],vy[k],cq,ox[j]*oy[k]);
}
}
int s=(n/sqrt(num))*+;
for(int i=;i<=num;++i) q[i].rt=(q[i].l-)/s;
sort(q+,q++num);
for(int i=;i<=num;++i){
while(px<q[i].l) now+=cy[w[++px]],++cx[w[px]];
while(py<q[i].r) now+=cx[w[++py]],++cy[w[py]];
while(px>q[i].l) --cx[w[px]],now-=cy[w[px--]];
while(py>q[i].r) --cy[w[py]],now-=cx[w[py--]];
ans[q[i].id]+=now*q[i].opt;
}
for(int i=;i<=cq;++i) print(ans[i]);
Ot();
return ;
}

洛谷P4689 [Ynoi2016]这是我自己的发明(树上莫队+树链剖分)的更多相关文章

  1. 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)

    洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...

  2. 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]

    传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...

  3. 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  4. [Ynoi2016]这是我自己的发明(莫队)

    话说这道题数据是不是都是链啊,我不手动扩栈就全 \(RE\)... 不过 \(A\) 了这题还是很爽的,通过昨晚到今天早上的奋斗,终于肝出了这题 其实楼上说的也差不多了,就是把区间拆掉然后莫队瞎搞 弱 ...

  5. Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】

    题目链接:洛谷 又来做Ynoi里面的水题了... 首先换根的话是一个套路,首先以1为根dfs,然后画一画就知道以rt为根,x的子树是什么了.可以拆分为2个dfs连续段. 然后如果要计算\([l_1,r ...

  6. 洛谷P3178 树上操作 [HAOI2015] 树链剖分

    正解:树链剖分+线段树 解题报告: 传送门! 树链剖分+线段树算是基操了趴,,, 就无脑码码码,没有任何含金量,不需要动脑子,然后码量其实也不大,就很爽 比树剖的板子还要板子一些hhhhh 放下代码就 ...

  7. 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)

    传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...

  8. 【洛谷1494】[国家集训队] 小Z的袜子(莫队)

    点此看题面 大致题意: 有\(N\)只从\(1\sim N\)编号的袜子,告诉你每只袜子的颜色,\(M\)组询问,每组询问给你一个区间\([L\sim R]\),让你求出小Z随机抽出\(2\)只袜子时 ...

  9. 洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P3178 这道题目是一道树链剖分的模板题. 但是在解决这道问题的同事刷新了我的两个认识: 第一个认识是:树链剖分不光可以处理链, ...

随机推荐

  1. ZUI(BootStrap)使用vue动态插入HTMl所创建的data-toggle事件初始化方法

    用ZUI的图片浏览:lightbox 写静态html的时候是有预览效果的,使用了vue动态加载就没有效果了, 网上的说法是动态生成的没有激活事件:ZUI(BootStrap)动态插入HTMl所创建的d ...

  2. 《PC Assembly Language》读书笔记

    本书下载地址:pcasm-book. 前言 8086处理器只支持实模式(real mode),不能满足安全.多任务等需求. Q:为什么实模式不安全.不支持多任务?为什么虚模式能解决这些问题? A: 以 ...

  3. [Cometoj#4 B]奇偶性_打表

    奇偶性 题目链接:https://cometoj.com/contest/39/problem/B?problem_id=1577 数据范围:略. 题解: 因为$f$的构造原因,很容易找到规律. 进而 ...

  4. [转帖]ubuntu 修改 apt源的方法

    https://www.cnblogs.com/dadonggg/p/11129973.html ubuntu 和 centos 是不一样的 ubunut 里面 用deb开头 放置到 /etc/apt ...

  5. java中讲讲PrintWriter的用法,举例?

    [学习笔记] 1.2 PrintWriter的用法 PrintWriter和PrintStream类似,只不过PrintStream是针对字节流的,而PrintWriter是针对字符流的. 例:1.2 ...

  6. Thinking In Java 4th Chap3 操作符

    若String后接一‘+’运算符,其后元素自动转化为String类型 注意:若对对象赋值另一对象,操作对应的是引用,如c=d,则c和d都指向原来d指向的对象 生成随机数:Random rand=new ...

  7. LC 1. Two Sum

    题目介绍 Given an array of integers, return indices of the two numbers such that they add up to a specif ...

  8. 恩佐夫博弈+JAVA大数

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=5973 根号5复制后200位就行了,因为BigDecimal不支持开根号,除法二分开根. import ja ...

  9. MySQL SELECT语法(一)SELECT语法详解

    源自MySQL 5.7 官方手册:13.2.9 SELECT Syntax SELECT的语法如下: SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIO ...

  10. Node.js学习(1)-加载模块require('fs/http/.b/art-template')

    node.js既不是语言,也不是框架,它是一个平台 加载模块: 核心模块(require('fs/http')), 自定义模块(var bExport=require('./b'),exports.f ...