试题描述
在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. NYOJ 5 字符串处理 find()函数应用

    http://acm.nyist.net/JudgeOnline/problem.php?pid=5 #include<stdio.h> #include<iostream> ...

  2. HDOJ 3790

    dijstra最短路径算法 : 9885560 2013-12-23 23:54:56 Accepted 3790 203MS 8112K 1343 B C++ 泽泽 #include<cstd ...

  3. Controller之间传递数据:协议传值

    http://itjoy.org/?p=416 前边介绍过从第一个页面传递数据到第二个页面,那么反过来呢我们该如何操作?还是同一个例子,将第二个页面的字符串传递到第一个页面显示出来,这中形式就可以使用 ...

  4. JavaScript Math 对象方法

    Math 对象方法 方法 描述 abs(x) 返回数的绝对值. acos(x) 返回数的反余弦值. asin(x) 返回数的反正弦值. atan(x) 以介于 -PI/2 与 PI/2 弧度之间的数值 ...

  5. 【转】Linux中如何安装.rpm、.tar、.tar.gz和tar.bz2

    我以下面三个包为例:(三个包都在/etc/opt下)A.example-1.2.3-1.rpmB.example-1.2.3-1.tarC.example-1.2.3-1.tar.gz 1.对于rpm ...

  6. 利用jQuery.validate异步验证用户名是否存在

    转:http://www.cnblogs.com/linzheng/archive/2010/10/14/1851781.html HTML头部引用: <script type="te ...

  7. Java for LeetCode 053 Maximum Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  8. 【图文详解】python爬虫实战——5分钟做个图片自动下载器

    python爬虫实战——图片自动下载器 之前介绍了那么多基本知识[Python爬虫]入门知识,(没看的先去看!!)大家也估计手痒了.想要实际做个小东西来看看,毕竟: talk is cheap sho ...

  9. 桶排序(bucket sort)

    Bucket Sort is a sorting method that subdivides the given data into various buckets depending on cer ...

  10. HTML CSS 中DIV内容居中汇总

    转载博客(http://www.cnblogs.com/dearxinli/p/3865099.html) (备注:DIV居中情况,网上谈到也比较多,但是这篇文字,相对还是挺全面,现转载,如果冒犯,还 ...