YNOI2016 这是我自己的发明
看到这个标题立刻想到:、
“绝地科学家,八倍不屏息啊,八百里外把头打啊...”
首先我们发现如果只考虑第二个操作,这棵树就是假的,我们可以直接莫队解决
如果考虑换根的话...可以把一个操作换成小于等于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[] , *p1 , *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf , , , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
int ret = ; char ch = nc();
while(!isdigit(ch)) ch = nc();
while(isdigit(ch)) ret = ((ret + (ret << )) << ) + (ch ^ '') , ch = nc();
return ret;
}
char pbuf[] , *pp = pbuf;
inline void push(const char ch)
{
if(pp == pbuf + ) fwrite(pbuf , , , stdout) , pp = pbuf;
*pp ++ = ch;
}
inline void write(long long x)
{
static char sta[];
int top = ;
if(!x) push('');
while(x) sta[++top] = x % ^ '' , x /= ;
while(top) push(sta[top -- ]);
push('\n');
}
const int maxn = ;
int n,m,rt;
int qx;
int a[maxn],vi[maxn];
int q_size;
int first[maxn],to[maxn << ],nx[maxn << ],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 & )
return r < b.r;
return r > b.r;
}
return l < b.l;
}
}qs[maxn * ];
int fa[maxn][],dep[maxn],ind[maxn],oud[maxn],reh[maxn],dfn;
inline void dfs(int x)
{
ind[x] = ++dfn;reh[dfn] = a[x];
for(int i=;i<=;i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i=first[x];i;i=nx[i])
{
if(to[i] == fa[x][])continue;
dep[to[i]] = dep[x] + ;
fa[to[i]][] = x;
dfs(to[i]);
}oud[x] = dfn;
}
LL ans[maxn * ];
LL now;int cnt_x[maxn],cnt_y[maxn];
inline int go_anc(int x , int y)
{
int i;
for(i = ; ~i ; i -- )
if(dep[y] - dep[x] > ( << i))
y = fa[y][i];
return y;
}
int xpos[],ypos[],opt_x[],opt_y[];
int main()
{
freopen("1.in","r",stdin);
freopen("www.out","w",stdout);
int tx,ty;
n = read(),m = read();
for(int i=;i<=n;i++)vi[i] = a[i] = read();
sort(vi + ,vi + n + );
for(int i=;i<=n;i++)a[i] = lower_bound(vi + ,vi + n + ,a[i]) - vi;
for(int i=;i<=n;i++)
{
int u = read(),v = read();
ins(u,v);
}dfs(rt = );
//return 0;
for(int i=;i<=m;i++)
{
int t = read(),x = read();
if(t == ){rt = x;continue;}
int y = read(),z;q_size++;
tx = ty = ;
if(x == rt) xpos[++tx] = n , opt_x[tx] = ;
else if(ind[rt] < ind[x] || ind[rt] > oud[x]) xpos[++tx] = oud[x] , opt_x[tx] = , xpos[++tx] = ind[x] - , opt_x[tx] = -;
else z = go_anc(x , rt) , xpos[++tx] = n , opt_x[tx] = , xpos[++tx] = oud[z] , opt_x[tx] = - , xpos[++tx] = ind[z] - , opt_x[tx] = ; if(y == rt) ypos[++ty] = n , opt_y[ty] = ;
else if(ind[rt] < ind[y] || ind[rt] > oud[y]) ypos[++ty] = oud[y] , opt_y[ty] = , ypos[++ty] = ind[y] - , opt_y[ty] = -;
else z = go_anc(y , rt) , ypos[++ty] = n , opt_y[ty] = , ypos[++ty] = oud[z] , opt_y[ty] = - , ypos[++ty] = ind[z] - , opt_y[ty] = ; for(int j=;j<=tx;j++)
for(int k=;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=;i<=qx;i++)qs[i].bl = (qs[i].l - ) / si;
sort(qs + ,qs + qx + );
int l = ,r = ;
for(int i=;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=;i<=q_size;i++)write(ans[i]);
fwrite(pbuf , , pp - pbuf , stdout);
}
YNOI2016 这是我自己的发明的更多相关文章
- 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)
洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...
- [Ynoi2016]这是我自己的发明 莫队
传送门:here 很棒的莫队题啊..... 题意: 有一棵$ n$个点的树,树上每个点有点权,有$ m$次询问: 操作1:给定两个点$ x,y$,求二元组$ (a,b)$的数量,要求$ a$在$ x$ ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]
传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...
- bzoj4940: [Ynoi2016]这是我自己的发明
用dfs序把询问表示成询问dfs序的两个区间中的信息 拆成至多9个询问(询问dfs序的两个前缀),对这些询问用莫队处理,时间复杂度$O(n\sqrt{m})$ #include<bits/std ...
- [Ynoi2016]这是我自己的发明(莫队)
话说这道题数据是不是都是链啊,我不手动扩栈就全 \(RE\)... 不过 \(A\) 了这题还是很爽的,通过昨晚到今天早上的奋斗,终于肝出了这题 其实楼上说的也差不多了,就是把区间拆掉然后莫队瞎搞 弱 ...
- 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法
题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...
- Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】
题目链接:洛谷 又来做Ynoi里面的水题了... 首先换根的话是一个套路,首先以1为根dfs,然后画一画就知道以rt为根,x的子树是什么了.可以拆分为2个dfs连续段. 然后如果要计算\([l_1,r ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明(树上莫队+树链剖分)
题目描述 您正在打galgame,然后突然家长进来了,于是您假装在写数据结构题: 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1.将树根换为 x. 2.给出两个点 x,y,从 ...
- bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...
随机推荐
- python设置环境变量
方法1: 当程序开发完毕,就可以添加到 '/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages'中 ...
- JavaEE应用基础平台 AOS-V0.1 RELEASED
写在最前面 AOS是一个有着悠久历史传承和发扬的平台.她的前世G4Studio自2010年公布V1.0版本号以来,先后经过多次版本号更新.并得到了一些小伙伴的认可和使用.但我们希望做得更好,走得更远. ...
- Dbvisualizer 连接oracle数据库
软件及驱动下载: 链接:https://pan.baidu.com/s/1OhuRDCd6FDi21NyCEdN2dA 密码:0rtp 软件破解办法: 1. 找到<C:\Program File ...
- hdu 4414 Finding crosses【简单模拟】
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4414 CSUST:点击打开链接 Finding crosses Time Limit: 2000/1000 ...
- Win10 Edge浏览器 应用商店 IE浏览器 无法访问页面 0x8000FFFF 问题解决
- Pipeline outbound
netty源码死磕8 Pipeline outbound 出站流程揭秘 1. Pipeline outbound流程 1.1. 出站的定义 简单回顾一下. 出站(outbound) 操作,通常是处于上 ...
- Redis 配置和使用
Redis的配置 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者me ...
- PAT 1053. 住房空置率 (20)
在不打扰居民的前提下,统计住房空置率的一种方法是根据每户用电量的连续变化规律进行判断.判断方法如下: 在观察期内,若存在超过一半的日子用电量低于某给定的阈值e,则该住房为“可能空置”: 若观察期超过某 ...
- hdu 3718 Different Division
Different Division Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Notification状态栏显示信息
Notification即通知,用于在通知栏显示提示信息. 在API Level > 11,Notification类中的一些方法被Android声明deprecated(弃用),而在API L ...