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. sizeof()和lstrlen()和strlen()区别

    strlen()是返回字符串的字节长度,   lstrlen()是返回字符串的字符长度.   也就是说第二个函数可能和第一个函数结果一样,如果字符串中字符单位都是单字节的话.       一般来说主要 ...

  2. 解决FileExplorer窗口变小问题

    3.解决FileExplorer窗口变小问题 须在$HOME/.vimrc中添加: "解决FileExplorer窗口变小问题 let g:bufExplorerMaxHeight=30 l ...

  3. QRowTable表格控件(三)-效率优化之-合理使用QStandardItem

    目录 一.开心一刻 二.概述 三.效果展示 四.QStandardItem 1.QStandardItem是什么鬼 2.性能分析 3.QStandardItem使用上的坑 五.相关文章 原文链接:QR ...

  4. Vmware centos7无法联网的问题解决

    VMware三种网络连接方式的区别 : 1) bridge : 默认使用VMnet0,不提供DHCP服务 在桥接模式下,虚拟机和宿主计算机处于同等地位,虚拟机就像是一台真实主机一样存在于局域网中.因此 ...

  5. [LeetCode] 107 Binary Tree Level Order Traversal II (easy)

    原题 层序遍历,从自底向上按层输出. 左→右→中 解法一 : DFS,求出自顶向下的,最后返回时反转一下. class Solution { public: vector<vector<i ...

  6. hdu6383 p1m2(二分答案)

    p1m2 题目传送门 解题思路 因为x都是非负数,且每一次操作其实就是把总和减少了1,所以可以得出最后都可以到达稳定.最后稳定的数的下界是0,最大也不会超过其初始数的最大值,所以可以用二分答案来求解. ...

  7. 前端手势控制图片插件书写四(图片上传及Ios图片方向问题)

    1.在图片上传中,使用的input的type为File的属性.使用filereader的Api let that = this; var file = document.getElementById( ...

  8. Simple TPU的设计和性能评估

    深度学习飞速发展过程中,人们发现原有的处理器无法满足神经网络这种特定的大量计算,大量的开始针对这一应用进行专用的硬件设计.谷歌的张量处理单元(Tensor Processing Unit,后文简称TP ...

  9. 重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关

    重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关 引言 重复造轮子系列是自己平时的一些总结.有的轮子依赖社区提供的轮子为基础,这里把使用过程的一些觉得有意思的做个分享.有些思路或者方法在 ...

  10. 头部姿态估计 - OpenCV/Dlib/Ceres

    基本思想 通过Dlib获得当前人脸的特征点,然后通过旋转平移标准模型的特征点进行拟合,计算标准模型求得的特征点与Dlib获得的特征点之间的差,使用Ceres不断迭代优化,最终得到最佳的旋转和平移参数. ...