题目描述

您正在打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. kafka server.properties 配置文件详解(二)

    虽然在前面一部分我们启动了kafka集群,并通过控制台的方式实现了producer和consumer,但是我们还是了解一下kafka单个节点是的配置参数属性, 也只有了解了这些参数的配置,才能将kaf ...

  2. IDEA Java 源发行版 8 需要目标发行版 1.8

     [问题记录] maven新建的一个项目,需要到一些java8的一些特性,但是在编译的时候就报错了,提示这样的错误. 我是在用二进制字面量出现的这个问题,二进制自变量是Java7的特性, 你可以这样写 ...

  3. LINUX添加新的用户账号并赋予root权限

    一:添加新的用户账号使用 useradd 命令 语法:     useradd  选项  用户名 示例:      # 添加用户,设定登录目录:useradd -d  /home/admin -m a ...

  4. 真理胜于一切 JAVA模拟表单提交

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  5. Scala当中什么是Transformation和 Action,以及它们俩的区别是什么?

    [学习笔记] 一个完整的RDD任务由两部分组成:Transformation和 Action.Transformation用于对RDD的创建,还可以把老的RDD通过Transformation来生成新 ...

  6. MyBatis 源码篇-SQL 执行的流程

    本章通过一个简单的例子,来了解 MyBatis 执行一条 SQL 语句的大致过程是怎样的. 案例代码如下所示: public class MybatisTest { @Test public void ...

  7. element-ui当中table组件的合并行和列的属性:span-method的用法

    背景 最近基本上都是以Vue来构建项目,而UI框架也基本上都是使用的element-ui,所以里面组件用的也是越来越多,今天想记录的是非常非常小的一个属性的用法. Table组件 Table组件用了真 ...

  8. Skywalking的增强与拦截机制

    整理自架构经理(汤哥)的分享 字节增强条件匹配 在 skywalking 中实现很多基于 byte-buddy 的关于链式匹配查询的实现, 代码如下所示: public abstract class ...

  9. ASP.NET Core 2.0 中读取 Request.Body 的正确姿势

    原文:ASP.NET Core 中读取 Request.Body 的正确姿势 ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream ...

  10. vue路径中的#号

    最近学习vue过程中,发现路径当中总是存在一个#号,比如这个: 这种情况是因为在入口js文件中,如果你不更改设置的话,vue会默认使用hash模式,该模式下回将路径格式化为 # 开头. 如果需要美化路 ...