这题和 COT1 一定有 JQ 喵~

线段树的启发式合并,每次要连接两个点时就对比较小的那棵树暴力 DFS 一边

然后均摊时间依旧是 logn 的,均摊真是世界上最邪恶的东西了……

然后这题的数据是要卖萌么?!
testcase 的存在意义是被阿卡林噎掉了么?!

 #include <cstdio>
#include <cstring>
#include <algorithm>
const int sizeOfPoint=;
const int sizeOfEdge=;
const int sizeOfNode=; inline int lg(int);
inline void swap(int & , int & );
inline char getch();
inline int getint();
inline void putint(int); struct edge {int point; edge * next;};
edge memory_edge[sizeOfEdge], * port_edge=memory_edge;
inline edge * newedge(int, edge * );
inline void link(int, int); struct node {int c; node * l , * r; inline node();};
node * null=new node();
node memory_node[sizeOfNode], * port_node=memory_node;
inline node * newnode(node * =null);
node * insert(node * , int, int, int); int b[sizeOfPoint], s[sizeOfPoint];
int find(int);
inline void merge(int, int); int testcase;
int N, M, T, U;
int p[sizeOfPoint], q[sizeOfPoint];
int f[sizeOfPoint], d[sizeOfPoint], a[][sizeOfPoint];
edge * e[sizeOfPoint];
node * t[sizeOfPoint];
inline void clear();
inline bool cmp(int, int);
inline void discretization();
void dfs(int);
inline int lca(int, int);
inline int query(int, int, int); int main()
{
int lastans=; testcase=getint();
for (testcase=;testcase;testcase--)
{
N=getint(), M=getint(), T=getint();
clear();
for (int i=;i<=N;i++)
p[i]=getint();
for (int i=;i<=M;i++)
{
int u=getint(), v=getint();
link(u, v);
}
discretization(); for (int i=;i<=N;i++) if (f[i]==-)
{
f[i]=; d[i]=;
dfs(i);
} for (int i=;i<=T;i++)
{
char c=getch(); int x=getint()^lastans, y=getint()^lastans;
if (c=='Q')
{
int k=getint()^lastans;
lastans=query(x, y, k);
putint(lastans);
}
else
{
int bx=find(x), by=find(y);
if (bx==by) continue;
if (s[bx]<s[by]) swap(x, y);
link(x, y);
f[y]=x; d[y]=d[x]+;
dfs(y);
}
}
} return ;
} inline int lg(int x)
{
return -__builtin_clz(x);
}
inline void swap(int & x, int & y)
{
int z=x;
x=y;
y=z;
}
inline char getch()
{
register char ch;
do ch=getchar(); while (ch!='L' && ch!='Q');
return ch;
}
inline int getint()
{
register int num=;
register char ch=, last;
do last=ch, ch=getchar(); while (ch<'' || ch>'');
do num=num*+ch-'', ch=getchar(); while (ch>='' && ch<='');
if (last=='-') num=-num;
return num;
}
inline void putint(int num)
{
char stack[];
register int top=;
if (num==) stack[top=]='';
if (num<) putchar('-'), num=-num;
for ( ;num;num/=) stack[++top]=num%+'';
for ( ;top;top--) putchar(stack[top]);
putchar('\n');
} inline edge * newedge(int point, edge * next)
{
edge * ret=port_edge++;
ret->point=point; ret->next=next;
return ret;
}
inline void link(int u, int v)
{
e[u]=newedge(v, e[u]);
e[v]=newedge(u, e[v]);
merge(u, v);
} inline node::node()
{
this->c=;
this->l=this;
this->r=this;
}
inline node * newnode(node * t)
{
node * newt=port_node++;
*newt=*t;
return newt;
}
node * insert(node * t, int l, int r, int k)
{
t=newnode(t);
t->c++;
if (l==r) return t; int m=(l+r)>>;
if (k<=m) t->l=insert(t->l, l, m, k);
else t->r=insert(t->r, m+, r, k);
return t;
} int find(int u)
{
return !b[u]?u:b[u]=find(b[u]);
}
inline void merge(int u, int v)
{
u=find(u); v=find(v);
b[v]=u; s[u]+=s[v];
} inline void clear()
{
port_edge=memory_edge;
memset(e, , sizeof(e));
port_node=memory_node;
for (int i=;i<=N;i++) t[i]=null;
memset(f, -, sizeof(f));
memset(d, -, sizeof(d));
memset(b, , sizeof(b));
memset(a, , sizeof(a));
for (int i=;i<=N;i++) s[i]=;
}
inline bool cmp(int a, int b)
{
return p[a]<p[b];
}
inline void discretization()
{
static int k[sizeOfPoint]; for (int i=;i<=N;i++) k[i]=i;
std::sort(k+, k+N+, cmp); q[U=]=p[k[]]; p[k[]]=;
for (int i=;i<=N;i++)
{
if (p[k[i]]>q[U]) q[++U]=p[k[i]];
p[k[i]]=U;
}
}
void dfs(int u)
{
t[u]=insert(t[f[u]], , U, p[u]);
if (d[u]>)
{
int lim=lg(d[u]);
a[][u]=f[u];
for (int i=;i<=lim;i++)
a[i][u]=a[i-][a[i-][u]];
for (int i=lim+;i<;i++)
a[i][u]=;
} for (edge * i=e[u];i;i=i->next) if (i->point!=f[u])
{
f[i->point]=u;
d[i->point]=d[u]+;
dfs(i->point);
}
}
inline int lca(int u, int v)
{
if (d[u]<d[v]) swap(u, v);
while (int dist=d[u]-d[v]) u=a[__builtin_ctz(dist)][u];
if (u==v) return u;
for (int i=;i>=;i--)
if (a[i][u]!=a[i][v])
u=a[i][u],
v=a[i][v];
return f[u];
}
inline int query(int a, int b, int k)
{
int c=lca(a, b), d=f[c];
node * ta=t[a], * tb=t[b], * tc=t[c], * td=t[d];
int l=, r=U, m; for ( ;l<r; )
{
m=(l+r)>>;
if (ta->l->c+tb->l->c-tc->l->c-td->l->c>=k)
{
ta=ta->l; tb=tb->l; tc=tc->l; td=td->l;
r=m;
}
else
{
k-=ta->l->c+tb->l->c-tc->l->c-td->l->c;
ta=ta->r; tb=tb->r; tc=tc->r; td=td->r;
l=m+;
}
} return q[l];
}

又 R 又 T 一时爽

[BZOJ 3123]森林的更多相关文章

  1. BZOJ 3123 森林(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...

  2. BZOJ - 3123 森林 (可持久化线段树+启发式合并)

    题目链接 先把初始边建成一个森林,每棵树选一个根节点递归建可持久化线段树.当添加新边的时候,把结点数少的树暴力重构,以和它连边的那个点作为父节点继承线段树,并求出倍增数组.树的结点数可以用并查集来维护 ...

  3. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

  4. 【sdoi2013】森林 BZOJ 3123

    Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...

  5. BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]

    3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...

  6. bzoj 3123: [Sdoi2013]森林(45分暴力)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4184  Solved: 1235[Submit][Status ...

  7. AC日记——[Sdoi2013]森林 bzoj 3123

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3216  Solved: 944[Submit][Status] ...

  8. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  9. ●BZOJ 3123 [Sdoi2013]森林

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3123 题解: 主席树,在线,启发式合并 简单版(只有询问操作):[2588: Spoj 10 ...

随机推荐

  1. String使用机制及string.equals()和==的区别(转)

    http://904582819.blog.163.com/blog/static/11159282020127794456840/ equals方法和==的区别   首先大家知道,String既可以 ...

  2. 前端和后台对时间数值的增减操作(JavaScript和C#两种方法)

    最近在做一个视频回放项目,记录下一点总结. 应用背景: 假设有一个门禁系统记录着门禁的人员进出刷卡信息,门禁装有视频录像设备,现在要根据人员的刷卡时间调出其刷卡时间点前后一段时间的录像.关于视频回放部 ...

  3. shell 随机从数组中抽取三个随机数(#可持续不停抽取)

    #!/bin/bash #b= ]] #do #sleep 1 student=( DPL YPD LT ZZM HY CQW LSJ ybr) a=$[RANDOM%+] c=$[RANDOM%+] ...

  4. Java学习1 - java 历史

    Sun的Java语言开发小组成立于1991年,其目的是开拓消费类电子产品市场,例如:交互式电视,烤面包箱等.Sun内部人员把这个项目称为 Green,那时World Wide Web还在图纸上呢.该小 ...

  5. cocos2d-x 常用UI

    CCSprite* sprite = CCSprite::create("CloseNormal.png"); sprite->setPosition(ccp(50, 50) ...

  6. 用户、角色、权限三者多对多用hibernate的一对多注解配置

    用户.角色.权限三者多对多用hibernate的一对多注解配置 //权限表@Table(name = "p")public class P { @Id @GeneratedValu ...

  7. UIKit框架之UIEvent

    1.继承链:NSObject 2.事件大致可以分为三种事件:触摸事件.动作事件.遥控事件 3.获取事件的touches (1)- (NSSet<UITouch *> *)allTouche ...

  8. linux中解压缩并安装.tar.gz后缀的文件

    1.解压缩: Linux下以tar.gz为扩展名的软件包,是用tar程序打包并用gzip程序压缩的软件包.要安装这种软件包,需要先对软件包进行解压缩,使用“tar -zxfv filename.tar ...

  9. 浅谈FTP 与 LFTP 的 nlist 和 mget 功能

    最近因为业务需要,与第三方数据厂商做数据对接,接口方式协定为 FTP传输 ,说说我过程中的dan teng 经历. 开始准备用 lftp mirror 的方式镜像的方式同步数据,由于对方提供的日志文件 ...

  10. Unity3D教程:茄子童萌會

    http://s.epb.idv.tw/han-shi-ku/unity Unity 0000 Unity3D學習之路 - C#學習筆記(一) 0001 Unity3D學習之路 - C#學習筆記(二) ...