试题描述
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
输入
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
输出
对于每组询问,输出一个整数表示答案。
输入示例
10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
输出示例
6
1
-1
8
其他说明
N<=100000, M,Q<=500000,h_i,c,x<=10^9

在线算法:

做一次最小生成树,考虑在连边x,y时新建节点ToT,连接ToT->findset(x),ToT->findset(y),将ToT的权值赋为边(x,y)的权值

这样有什么好处呢?对于x走不超过v的边能到达的节点就是x向上倍增最上面一个rt的子树的叶结点,DFS序+主席树就可以做k大了。

这是正常版的O(nlogn)(2481ms)

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
inline void print(int x) {
if(x==){putchar('');return;}if(x<) putchar('-'),x=-x;
int len=,buf[];while(x) buf[len++]=x%,x/=;
for(int i=len-;i>=;i--) putchar(buf[i]+'');putchar('\n');
}
const int maxn=;
const int maxm=;
const int maxnode=;
struct Edge {
int u,v,w;
bool operator < (const Edge& ths) const {
return w<ths.w;
}
}e[maxm];
int n,m,q,ToT,h[maxn],val[maxn],pa[maxn];
int lastans,tmp[maxn];
int findset(int x) {return x==pa[x]?pa[x]:pa[x]=findset(pa[x]);}
int first[maxn],next[maxn],to[maxn],es;
void AddEdge(int u,int v) {
to[++es]=v;next[es]=first[u];first[u]=es;
}
int fa[maxn][],Ln[maxn],Rn[maxn],vis[maxn],sz;
int root[maxn<<],ls[maxnode],rs[maxnode],s[maxnode],TOT;
void update(int& y,int x,int l,int r,int pos) {
s[y=++TOT]=s[x]+;if(l==r) return;
int mid=l+r>>;ls[y]=ls[x];rs[y]=rs[x];
if(pos<=mid) update(ls[y],ls[x],l,mid,pos);
else update(rs[y],rs[x],mid+,r,pos);
}
int query(int x,int y,int l,int r,int k) {
if(l==r) return l;
int k2=s[rs[y]]-s[rs[x]],mid=l+r>>;
if(k2>=k) return query(rs[x],rs[y],mid+,r,k);
return query(ls[x],ls[y],l,mid,k-k2);
}
void dfs(int x) {
Ln[x]=++sz;vis[x]=;
if(x<=n) update(root[sz],root[sz-],,n,lower_bound(tmp+,tmp+n+,h[x])-tmp);
else root[sz]=root[sz-];
rep(,) fa[x][i]=fa[fa[x][i-]][i-];
ren fa[to[i]][]=x,dfs(to[i]);
Rn[x]=++sz;root[sz]=root[sz-];
}
int findrt(int x,int v) {
for(int i=;i>=;i--) if(val[fa[x][i]]<=v) x=fa[x][i];
return x;
}
int main() {
val[]=2e9;
n=ToT=read();m=read();q=read();
rep(,n) tmp[i]=h[i]=read(),pa[i]=i;
sort(tmp+,tmp+n+);
rep(,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
sort(e+,e+m+);
rep(,m) {
int u=findset(e[i].u),v=findset(e[i].v);
if(u!=v) {
val[++ToT]=e[i].w;pa[ToT]=ToT;
AddEdge(ToT,u);AddEdge(ToT,v);
pa[u]=pa[v]=ToT;
}
}
rep(,n) if(!vis[i]) dfs(findset(i));
rep(,q) {
int v=read(),x=read(),k=read();
int rt=findrt(v,x),r1=root[Ln[rt]-],r2=root[Rn[rt]];
if(s[r2]-s[r1]<k) print(lastans=-);
else print(lastans=tmp[query(r1,r2,,n,k)]);
}
return ;
}

这是自己写人工栈版的(本机第一种写法会爆栈,无法出数据)O(nlogn)(2606ms)

#include<cstdio>
#include<cctype>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
const int maxm=;
const int maxnode=;
struct Edge {
int u,v,w;
bool operator < (const Edge& ths) const {
return w<ths.w;
}
}e[maxm];
int n,m,q,ToT,h[maxn],val[maxn],pa[maxn];
int lastans,tmp[maxn];
int findset(int x) {return x==pa[x]?pa[x]:pa[x]=findset(pa[x]);}
int first[maxn],next[maxn],to[maxn],es;
void AddEdge(int u,int v) {
to[++es]=v;next[es]=first[u];first[u]=es;
}
int fa[maxn][],Ln[maxn],Rn[maxn],vis[maxn],sz;
int root[maxn<<],ls[maxnode],rs[maxnode],s[maxnode],TOT;
void update(int& y,int x,int l,int r,int pos) {
s[y=++TOT]=s[x]+;if(l==r) return;
int mid=l+r>>;ls[y]=ls[x];rs[y]=rs[x];
if(pos<=mid) update(ls[y],ls[x],l,mid,pos);
else update(rs[y],rs[x],mid+,r,pos);
}
int query(int x,int y,int l,int r,int k) {
if(l==r) return l;
int k2=s[rs[y]]-s[rs[x]],mid=l+r>>;
if(k2>=k) return query(rs[x],rs[y],mid+,r,k);
return query(ls[x],ls[y],l,mid,k-k2);
}
stack<int> S;
void dfs(int x) {
S.push(x);
while(!S.empty()) {
x=S.top();
if(!vis[x]) {
vis[x]=;Ln[x]=++sz;
if(x<=n) update(root[sz],root[sz-],,n,lower_bound(tmp+,tmp+n+,h[x])-tmp);
else root[sz]=root[sz-];
rep(,) fa[x][i]=fa[fa[x][i-]][i-];
ren fa[to[i]][]=x,S.push(to[i]);
}
else Rn[x]=++sz,root[sz]=root[sz-],S.pop();
}
}
int findrt(int x,int v) {
for(int i=;i>=;i--) if(val[fa[x][i]]<=v) x=fa[x][i];
return x;
}
int main() {
val[]=2e9;
n=ToT=read();m=read();q=read();
rep(,n) tmp[i]=h[i]=read(),pa[i]=i;
sort(tmp+,tmp+n+);
rep(,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
sort(e+,e+m+);
rep(,m) {
int u=findset(e[i].u),v=findset(e[i].v);
if(u!=v) {
val[++ToT]=e[i].w;pa[ToT]=ToT;
AddEdge(ToT,u);AddEdge(ToT,v);
pa[u]=pa[v]=ToT;
}
}
rep(,n) if(!vis[i]) dfs(findset(i));
rep(,q) {
int v=read(),x=read(),k=read();
int rt=findrt(v,x),r1=root[Ln[rt]-],r2=root[Rn[rt]];
if(s[r2]-s[r1]<k) printf("%d\n",lastans=-);
else printf("%d\n",lastans=tmp[query(r1,r2,,n,k)]);
}
return ;
}

离线算法:

考虑将操作与边升序排序,离线用平衡树维护每个连通块的答案,连边时启发式合并即可

写成了int ans[maxn]调哭了233 O(nlog^2n)(1607ms)

#include<cstdio>
#include<cctype>
#include<queue>
#include<ctime>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
const int maxnode=;
const int maxm=;
struct Node {
Node* ch[];
int r,s,v;
void maintain() {s=ch[]->s+ch[]->s+;}
}nodes[maxnode],*null=&nodes[];
queue<Node*> Q;
int ToT;
Node* newnode(int v) {
Node* o;
if(!Q.empty()) o=Q.front(),Q.pop();
else o=&nodes[++ToT];
o->v=v;o->ch[]=o->ch[]=null;o->s=;o->r=rand();
return o;
}
void del(Node* &o) {Q.push(o);o=null;}
void rotate(Node* &o,int d) {
Node* k=o->ch[d^];o->ch[d^]=k->ch[d];k->ch[d]=o;
o->maintain();k->maintain();o=k;
}
void insert(Node* &o,int v) {
if(o==null) o=newnode(v);
else {
int d=v>o->v;insert(o->ch[d],v);
if(o->ch[d]->r>o->r) rotate(o,d^);
else o->maintain();
}
}
int query(Node* &o,int k) {
if(k>o->s) return -;
if(k==o->ch[]->s+) return o->v;
if(k<=o->ch[]->s+) return query(o->ch[],k);
return query(o->ch[],k-o->ch[]->s-);
}
void merge(Node* &big,Node* &small) {
if(small==null) return;
merge(big,small->ch[]);merge(big,small->ch[]);
insert(big,small->v);del(small);
}
void print(Node* &o) {
if(o==null) return;
print(o->ch[]);
printf("%d ",o->v);
print(o->ch[]);
}
Node* root[maxn];
struct Edge {
int u,v,w,id;
bool operator < (const Edge& ths) const {
return w<ths.w;
}
}e[maxm],qs[maxm];
int n,m,q,h[maxn],pa[maxn],ans[maxm];
int findset(int x) {return x==pa[x]?x:pa[x]=findset(pa[x]);}
int main() {
srand(time());null->s=;
n=read();m=read();q=read();
rep(,n) pa[i]=i,root[i]=newnode(h[i]=read());
rep(,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
rep(,q) qs[i].u=read(),qs[i].w=read(),qs[i].v=read(),qs[i].id=i;
sort(e+,e+m+);sort(qs+,qs+q+);int cur=;
rep(,q) {
while(cur<m&&qs[i].w>=e[cur+].w) {
cur++;int u=findset(e[cur].u),v=findset(e[cur].v);
if(u==v) continue;
if(root[u]->s>root[v]->s) swap(u,v);
merge(root[v],root[u]);pa[u]=v;
}
ans[qs[i].id]=query(root[findset(qs[i].u)],qs[i].v);
}
rep(,q) printf("%d\n",ans[i]);
return ;
}

COJ980 WZJ的数据结构(负二十)的更多相关文章

  1. COJ975 WZJ的数据结构(负二十五)

    试题描述 输入一个字符串S,回答Q次问题,给你l,r,输出子序列[l,r]的最长连续回文串长度. 输入 第一行为一个字符串S. 第二行为一个正整数Q. 接下来Q行每行为l,r. 输出 对于每个询问,输 ...

  2. COJ976 WZJ的数据结构(负二十四)

    试题描述 输入一个字符串S,回答Q次问题,给你l,r,输出从Sl--Sr组成的串在S中出现了多少次. 输入 第一行为一个字符串S.第二行为一个正整数Q.接下来Q行每行为l,r. 输出 对于每个询问,输 ...

  3. COJ978 WZJ的数据结构(负二十二)

    试题描述 输入两个正整数N.K,以及N个整数Ai,求第K小数. 输入 第一行为两个正整数N.K.第二行为N个正整数Ai. 输出 输出第K小数. 输入示例 5 41 2 3 3 5 输出示例 3 其他说 ...

  4. COJ 1002 WZJ的数据结构(二)(splay模板)

    我的LCC,LCT,Splay格式终于统一起来了... 另外..这个形式的Splay是标准的Splay(怎么鉴别呢?看Splay函数是否只传了一个变量node就行),刘汝佳小白书的Splay写的真是不 ...

  5. [COJ0988]WZJ的数据结构(负十二)

    [COJ0988]WZJ的数据结构(负十二) 试题描述 输入 见题目,注意本题不能用文件输入输出 输出 见题目,注意本题不能用文件输入输出 输入示例 输出示例 数据规模及约定 1≤N≤1500,M≤N ...

  6. COJ968 WZJ的数据结构(负三十二)

    WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有 ...

  7. [COJ0968]WZJ的数据结构(负三十二)

    [COJ0968]WZJ的数据结构(负三十二) 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变 ...

  8. [COJ0985]WZJ的数据结构(负十五)

    [COJ0985]WZJ的数据结构(负十五) 试题描述 CHX有一个问题想问问大家.给你一个长度为N的数列A,请你找到两个位置L,R,使得A[L].A[L+1].…….A[R]中没有重复的数,输出R- ...

  9. COJ966 WZJ的数据结构(负三十四)

    WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u  ...

随机推荐

  1. 用php实现百度网盘图片直链的代码分享

    第一种代码:代码量较少通过正则表达式获取百度网盘的文件真实地址,来实现直链的效果 将下面的代码保存为downbd.php 复制代码代码如下: <?php $canshu=$_SERVER[&qu ...

  2. shell 生成指定范围随机数与随机字符串 .

    shell 生成指定范围随机数与随机字符串         分类:             shell              2014-04-22 22:17     20902人阅读     评 ...

  3. CSS clearfix

    The problem happens when a floated element is within a container box, that element does not automati ...

  4. iOS UITableView 的beginUpdates和endUpdates

    在官方文档中是这样介绍beginUpdates的 Call this method if you want subsequent insertions, deletion, and selection ...

  5. Java for LeetCode 031 Next Permutation

    Next Permutation Total Accepted: 33595 Total Submissions: 134095     Implement next permutation, whi ...

  6. ubuntu命令行相关命令使用心得

    一.Ubuntu解压缩zip,tar,tar.gz,tar.bz2 ZIP zip可能是目前使用得最多的文档压缩格式.它最大的优点就是在不同的操作系统平台,比如Linux, Windows以及Mac ...

  7. touch详解

    touch事件 前言 一个触屏网站到底和传统的pc端网站有什么区别呢,交互方式的改变首当其冲.例如我们常用的click事件,在触屏设备下是如此无力. 手机上的大部分交互都是通过touch来实现的,于是 ...

  8. 安装phpredis模块

    [root@web01 src]# wget github.com/owlient/phpredis/tarball/master [root@web01 src]# tar -xzvf master ...

  9. SQL with as

    姓名 课程 分数 张三 语文 张三 数学 张三 物理 李四 语文 李四 数学 李四 物理 先看下面一个嵌套的查询语句 ) 上面的查询语句使用了一个子查询.虽然这条SQL语句并不复杂,但如果嵌套的层次过 ...

  10. 在linux上安装psycopg2出错--Error: pg_config executable not found.

    这个错误可能是因为缺少PGSQL的相关库吧. 网上有很多解决办法,我最终用以下方式解决: yum install postgresql postgresql-devel python-devel