hdu6703 array

题意

给定一个1到\(n\)的全排列,两种操作,将\(a_{pos}\)修改为\(a_{pos}+1000000\),询问第一个大于等于\(k\)的且不在\(a_1...a_r\)的数。

分析

  • 由于\(k<=n\),因此操作二询问的答案最大是\(n+1\),因此操作一就相当于删去一个数。
  • 考虑用权值线段树维护下标(权值区间下标最大值),操作一就将下标置为\(n+1\),而操作二就是在值域\([k,n]\)之间查询下标大于\(r\)的最小数。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int INF=0x3f3f3f3f;
int T,n,m,a[N],idx[N],o,p,r,k;
struct VCT{
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
int mx[N*4];
void pushup(int i){
mx[i]=max(mx[ls],mx[rs]);
}
void build(int i,int l,int r){
if(l==r){
mx[i]=idx[l];
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(i);
}
void update(int i,int l,int r,int p){
if(l==r && l==p){
mx[i]=n+1;
return;
}
if(p<=mid){
update(ls,l,mid,p);
}else{
update(rs,mid+1,r,p);
}
pushup(i);
}
//查询值域[ql,qr]中第一个大于k的下标
int query(int i,int l,int r,int k,int x){
if(l==r){
return l;
}
int ans=n+1;
if(k<=mid){
if(mx[ls]>x){
ans=min(ans,query(ls,l,mid,k,x));
//因为要找满足条件最小的值,左子树满足直接返回
if(ans<n+1){
return ans;
}
}
}
//这里不能else并列,因为进入左子树查询也有可能查到n+1
if(mx[rs]<=x){
return ans;
}
return query(rs,mid+1,r,k,x);
}
#undef ls
#undef rs
#undef mid
}wa;
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
idx[a[i]]=i;
}
idx[n+1]=INF;
n++;
wa.build(1,1,n);
int lst=0;
while(m--){
scanf("%d",&o);
if(o==1){
scanf("%d",&p);
p=p^lst;
wa.update(1,1,n,a[p]);
}else if(o==2){
scanf("%d%d",&r,&k);
r=r^lst;
k=k^lst;
lst=wa.query(1,1,n,k,r);
printf("%d\n",lst);
}
}
}
return 0;
}

hdu6704 K-th occurence

题意

给定一个字符串,多次询问其中一个子串第\(k\)次出现的位置。

分析

  • 子串出现位置考虑后缀数组,第\(k\)小考虑主席树。
  • 对于后缀数组来说,\(sa[i]\)表示后缀出现的位置,那么如果这个后缀对应的\(h[i]\)满足给定子串的长度,那就相当于这个子串出现的位置了。
  • 所以可以二分找到这个子串出现的位置区间,然后主席树维护后缀的出现位置\(sa[i]\),查询第\(k\)小即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int T,n,m,l,r,k,s[N];
char str[N];
int sa[N],rk[N],h[N];
int t[N],t2[N],c[N];
int tr[N];
int dp[N][25];
void build_sa(int n,int m=128){
n++;
int *x=t,*y=t2;
for(int i=0;i<m;i++){
c[i]=0;
}
for(int i=0;i<n;i++){
c[x[i]=s[i]]++;
}
for(int i=1;i<m;i++){
c[i]+=c[i-1];
}
for(int i=n-1;i>=0;i--){
sa[--c[x[i]]]=i;
}
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k;i<n;i++){
y[p++]=i;
}
for(int i=0;i<n;i++){
if(sa[i]>=k){
y[p++]=sa[i]-k;
}
}
for(int i=0;i<m;i++){
c[i]=0;
}
for(int i=0;i<n;i++){
c[x[y[i]]]++;
}
for(int i=1;i<m;i++){
c[i]+=c[i-1];
}
for(int i=n-1;i>=0;i--){
sa[--c[x[y[i]]]]=y[i];
}
swap(x,y);
p=1;
x[sa[0]]=0;
for(int i=1;i<n;i++){
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
}
if(p>=n){
break;
}
m=p;
}
n--;
for(int i=0;i<=n;i++){
rk[sa[i]]=i;
}
int k=0;
for(int i=0;i<n;i++){
if(k){
k--;
}
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]){
k++;
}
h[rk[i]]=k;
}
}
void debug(){
//sa 0~n 包括一个特殊字符
for(int i=0;i<=n;i++){
printf("%d ",sa[i]);
}
printf("\n");
//rk 0~n-1 后缀[i...n-1]的排名
for(int i=0;i<n;i++){
printf("%d ",rk[i]);
}
printf("\n");
//h 1~n 排名为i的后缀与排名为i-1的后缀的LCP
for(int i=1;i<=n;i++){
printf("%d ",h[i]);
}
printf("\n");
}
struct CT{
#define mid (l+r)/2
int tot,sum[N*30],lr[N*30],rr[N*30];
void init(){
tot=0;
}
int build(int l,int r){
int rt=++tot;
sum[rt]=lr[rt]=rr[rt]=0;
if(l==r){
return tot;
}
lr[rt]=build(l,mid);
rr[rt]=build(mid+1,r);
return rt;
}
int update(int pre,int l,int r,int v){
int rt=++tot;
sum[rt]=sum[pre]+1;
lr[rt]=lr[pre];
rr[rt]=rr[pre];
if(l>=r){
return rt;
}
if(v<=mid){
lr[rt]=update(lr[pre],l,mid,v);
}else{
rr[rt]=update(rr[pre],mid+1,r,v);
}
return rt;
}
int query(int u,int v,int l,int r,int k){
if(l>=r){
return l;
}
if(sum[v]-sum[u]<k){
return -1;
}
int lc=sum[lr[v]]-sum[lr[u]];
if(k<=lc){
return query(lr[u],lr[v],l,mid,k);
}else{
return query(rr[u],rr[v],mid+1,r,k-lc);
}
}
#undef mid
}ac;
void init(){
for(int i=0;i<=n;i++){
dp[i][0]=h[i];
}
for(int j=1;(1<<j)<=n;j++){
for(int i=0;i+(1<<j)-1<=n;i++){
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int rmq(int l,int r){
int k=0;
while((1<<(k+1))<=r-l+1){
k++;
}
return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int solve(int l,int r){
if(l==r){
return n-sa[l];
}
if(l>r){
swap(l,r);
}
return rmq(l+1,r);
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
scanf("%s",str);
for(int i=0;i<n;i++){
s[i]=str[i]-'a'+1;
}
s[n]=0;
build_sa(n);
// debug();
ac.init();
tr[0]=ac.build(1,n);
for(int i=1;i<=n;i++){
tr[i]=ac.update(tr[i-1],1,n,sa[i]+1);
}
init();
while(m--){
scanf("%d%d%d",&l,&r,&k);
l--;
r--;
int len=r-l+1;
int R=rk[l];
int ql=R,qr=R;
int ll=1,rr=R;
while(ll<=rr){
int md=(ll+rr)/2;
if(solve(md,R)>=len){
ql=md;
rr=md-1;
}else{
ll=md+1;
}
}
ll=R,rr=n;
while(ll<=rr){
int md=(ll+rr)/2;
if(solve(R,md)>=len){
qr=md;
ll=md+1;
}else{
rr=md-1;
}
}
if(qr-ql+1<k){
printf("-1\n");
continue;
}
int ans=ac.query(tr[ql-1],tr[qr],1,n,k);
printf("%d\n",ans);
}
}
return 0;
}

hdu6705 path

题意

给一个有向图,求第\(k\)小的路径。

分析

  • 这种题似乎都是优先队列来的...
  • 首先把所有点出边排序,最小的放进优先队列里,然后每次取出一条边\((u,v)\),加入\(u\)的下一条边和\(v\)的第一条边(如果有的话)。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+50;
struct Edge{
int v;
ll w;
bool operator <(const Edge &rhs)const{
return w<rhs.w;
}
};
vector<Edge> g[N];
int T,n,m,q,k,u,v,w;
struct node{
int u,id;
ll w;
bool operator <(const node &rhs)const{
return w>rhs.w;
}
};
int que[N];
ll ans[N];
priority_queue<node> pq;
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){
g[i].clear();
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(Edge{v,1ll*w});
}
int mx=0;
for(int i=1;i<=q;i++){
scanf("%d",&que[i]);
mx=max(mx,que[i]);
}
while(!pq.empty()){
pq.pop();
}
for(int i=1;i<=n;i++){
sort(g[i].begin(),g[i].end());
if(g[i].size()>0){
pq.push(node{i,0,g[i][0].w});
}
}
int kk=0;
//取一条加两条
while(!pq.empty()){
node tmp=pq.top();
pq.pop();
kk++;
ans[kk]=tmp.w;
/**
* if(kk==que[i].k){
* i++;
* if(i>q){
* break;
* }
* }
* 这种写法是错的,如果有多个相同的k,只会计算第一个的答案,后面死循环
*/
if(kk==mx){
break;
}
int u=tmp.u;
int id=tmp.id;
int v=g[u][id].v;
ll w=tmp.w;
if(g[u].size()>id+1){
pq.push(node{u,id+1,w-g[u][id].w+g[u][id+1].w});
}
if(g[v].size()>0){
pq.push(node{v,0,w+g[v][0].w});
}
}
for(int i=1;i<=q;i++){
printf("%lld\n",ans[que[i]]);
}
}
return 0;
}

hdu6703_array的更多相关文章

随机推荐

  1. NOIP2018普及T2暨洛谷P5016 龙虎斗

    题目链接:https://www.luogu.org/problemnew/show/P5016 分析: 这是一道模拟题.看到题目,我们首先要把它细致的读明白,模拟题特别考察细节,往往会有想不到的坑点 ...

  2. Elasticsearch 技术分析(九):Elasticsearch的使用和原理总结

    前言 之前已经分享过Elasticsearch的使用和原理的知识,由于近期在公司内部做了一次内部分享,所以本篇主要是基于之前的博文的一个总结,希望通过这篇文章能让读者大致了解Elasticsearch ...

  3. 俩台服务器搭建redis集群5.0.4

    俩台服务器搭建redis集群 1.俩服务器分别新建目录:usr/local/redis-cluster 2.下载源码并解压编译(使用redis版本5.0.4) 3.tar xzf redis-5.0. ...

  4. Java中的I/O输入输出流概述

    流是一组有序的数据序列,根据操作类型,可以分为输入流和输出流两种,Java语言中定义的负责各种输入输出的类都被放在java.io包中.其中所有的输入流类都是抽象类InputStream(字节输入流)或 ...

  5. PHP ErrorException 积累

    ErrorException [不定时更新] ErrorException1: Undefined index: allocate 描述:PHP默认会对未声明变量进行提示,这种默认的提示是可以进行忽略 ...

  6. 第二章 jQuery框架使用准备

    window常用属性: History:有关客户访问过的URL的信息 Location: 有关当前url的信息 常用方法: Confirm()将弹出一个确认对话框 open()在页面上弹出一个新的浏览 ...

  7. Cordova-iOS SDK封装

    源码编译与制作静态库 下载cordova-ios源码,下载地址为:cordova-ios 解压后使用Xcode进行编译,编译选定模拟器和Generic iOS Device,cmd+B,编译成功(Dy ...

  8. Eclipse Other Projects小问题

    Eclipse 不知什么时候多了个 "Other Projects" 文件夹,所有的项目又多了一层目录,如图所示: 虽然对功能没任何影响,但每次打开有些麻烦,多少感觉有些不爽…… ...

  9. SpringBoot Jar包瘦身 - 跟大文件说再见!

    前言 SpringBoot部署起来配置非常少,如果服务器部署在公司内网,上传速度还行,但是如果部署在公网(阿里云等云服务器上),部署起来实在头疼.就是 编译出来的 Jar 包很大,如果工程引入了许多开 ...

  10. Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)

    实践一下 Asp.Net Core (基于.net core 2.2)部署到Docker 一.准备工作: 1. 使用Virtualbox创建一个Centos系统的虚拟机,并安装docker和vim 2 ...