Description
题目描述
小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值。初始的时候,森林中有M条边。
小Z希望执行T个操作,操作有两类:
Q x y k查询点x到点y路径上所有的权值中,第k小的权值是多少。此操作保证点x和点y连通,同时这两个节点的路径上至少有k个点。L x y在点x和点y之间连接一条边。保证完成此操作后,仍然是一片森林。
为了体现程序的在线性,我们把输入数据进行了加密。设lastans为程序上一次输出的结果,初始的时候lastans为0。
- 对于一个输入的操作
Q x y k,其真实操作为Q x^lastans y^lastans k^lastans。 - 对于一个输入的操作
L x y,其真实操作为L x^lastans y^lastans。其中^运算符表示异或,等价于pascal中的xor运算符。
请写一个程序來帮助小Z完成这些操作。
对于所有的数据,n,m,T<=8*10^48∗104.
输入格式
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1<=testcase<=20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。
第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边。
接下来 T行,每行描述一个操作,格式为”Q x y k“或者”L x y “,其含义见题目描述部分。
输出格式
对于每一个第一类操作,输出一个非负整数表示答案。
Solution
对于每个点建立一棵权值线段树,将 它 到 它所在树的根 的路径上每个点的权值放入线段树中
并利用它的父亲的线段树的一部分来优化时间空间
每次连边操作用启发式合并来把复杂度优化到O(logn),修改较小数所有节点的权值线段树,方法同建树时
每次询问操作找lca,再将它们的权值线段树相减,在上面找第k大(注意对lca的处理)
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int N=8e4+10;
struct node
{
int v,id;
bool operator <(const node &o)const
{
return v<o.v;
}
}a[N];
int d[N],n,m,T,cnt,re[N],u,v,k,fa[N][17],top[N],si[N],rt[N],tot,dep[N];
vector <int> link[N];
bool flag[N];
char s[5];
struct mode
{
int lc,rc,sum;
}f[N*400];
void build(int l,int r,int &x,int y,int pos)
{
x=++tot,f[x]=f[y],f[x].sum++;
if(l==r) return ;
int mid=(l+r)>>1;
if(pos<=mid) build(l,mid,f[x].lc,f[y].lc,pos);
else build(mid+1,r,f[x].rc,f[y].rc,pos);
}
void dfs(int u,int fx)
{
flag[u]=true;
fa[u][0]=fx,si[u]=1,dep[u]=dep[fx]+1;
for(int i=1;i<17;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
build(1,cnt,rt[u],rt[fx],d[u]);
int size=link[u].size();
for(int i=size-1;i>=0;i--)
{
int v=link[u][i];
if(v==fx) continue;
top[v]=top[u];
dfs(v,u),si[u]+=si[v];
}
}
int get_top(int x)
{
return x==top[x]?x:top[x]=get_top(top[x]);
}
int Lca(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
for(int i=16;i>=0;i--)
if(dep[fa[y][i]]>=dep[x]) y=fa[y][i];
if(y==x) return x;
for(int i=16;i>=0;i--)
if(fa[y][i]!=fa[x][i])
y=fa[y][i],x=fa[x][i];
return fa[x][0];
}
int get(int lca1,int lca2,int x,int y,int l,int r,int k)
{
if(l==r) return l;
int mid=(l+r)>>1;
int cn=f[f[x].lc].sum+f[f[y].lc].sum-f[f[lca1].lc].sum-f[f[lca2].lc].sum;
if(k<=cn) return get(f[lca1].lc,f[lca2].lc,f[x].lc,f[y].lc,l,mid,k);
else return get(f[lca1].rc,f[lca2].rc,f[x].rc,f[y].rc,mid+1,r,k-cn);
}
int main()
{
scanf("%d",&T);
scanf("%d%d%d",&n,&m,&T);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].v),a[i].id=i;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
if(i==1 || a[i].v!=a[i-1].v) re[++cnt]=a[i].v;
d[a[i].id]=cnt;
}
while(m--)
{
scanf("%d%d",&u,&v);
link[u].push_back(v);
link[v].push_back(u);
}
for(int i=1;i<=n;i++)
if(!flag[i]) top[i]=i,dfs(i,0);
int last=0;
while(T--)
{
scanf("%s%d%d",s,&u,&v);
u^=last,v^=last;
if(s[0]=='L')
{
link[u].push_back(v);
link[v].push_back(u);
int fu=get_top(u),fv=get_top(v);
if(si[fu]<si[fv]) swap(fu,fv),swap(u,v);
top[v]=fu,si[fu]+=si[fv];
dfs(v,u);
}
else
{
scanf("%d",&k);
k^=last;
int lca=Lca(u,v);
last=re[get(rt[fa[lca][0]],rt[lca],rt[u],rt[v],1,cnt,k)];
printf("%d\n",last);
}
}
return 0;
}
来源:https://www.cnblogs.com/hsez-cyx/p/12271920.html